Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to implement memmove in standard C without an intermediate copy?
    primarykey
    data
    text
    <p>From the man page on my system:</p> <blockquote> <p>void *memmove(void *dst, const void *src, size_t len); </p> <p>DESCRIPTION<br> The memmove() function copies len bytes from string src to string dst.<br> <strong>The two strings may overlap</strong>; the copy is always done in a non-destructive<br> manner. </p> </blockquote> <p>From the C99 standard:</p> <blockquote> <p>6.5.8.5 When two pointers are compared, the result depends on the relative locations in the address space of the objects pointed to. If two pointers to object or incomplete types both point to the same object, or both point one past the last element of the same array object, theycompare equal. If the objects pointed to are members of the same aggregate object, pointers to structure members declared later compare greater than pointers to members declared earlier in the structure, and pointers to array elements with larger subscript values compare greater than pointers to elements of the same array with lower subscript values. All pointers to members of the same union object compare equal. If the expression <code>P</code> points to an element of an array object and the expression Q points to the last element of the same array object, the pointer expression <code>Q+1</code> compares greater than <code>P</code>. In all other cases, the behavior is <strong>undefined</strong>.</p> </blockquote> <p>The emphasis is mine.</p> <p>The arguments <code>dst</code> and <code>src</code> can be converted to pointers to <code>char</code> so as to alleviate strict aliasing problems, but is it possible to compare two pointers that may point inside different blocks, so as to do the copy in the correct order in case they point inside the same block?</p> <p>The obvious solution is <code>if (src &lt; dst)</code>, but that is undefined if <code>src</code> and <code>dst</code> point to different blocks. "Undefined" means you should not even assume that the condition returns 0 or 1 (this would have been called "unspecified" in the standard's vocabulary).</p> <p>An alternative is <code>if ((uintptr_t)src &lt; (uintptr_t)dst)</code>, which is at least unspecified, but I am not sure that the standard guarantees that when <code>src &lt; dst</code> is defined, it is equivalent to <code>(uintptr_t)src &lt; (uintptr_t)dst)</code>. Pointer comparison is defined from pointer arithmetic. For instance, when I read section 6.5.6 on addition, it seems to me that pointer arithmetic could go in the direction opposite to <code>uintptr_t</code> arithmetic, that is, that a compliant compiler might have, when <code>p</code> is of type <code>char*</code>:</p> <pre><code>((uintptr_t)p)+1==((uintptr_t)(p-1) </code></pre> <p>This is only an example. Generally speaking very little seems to be guaranteed when converting pointers to integers.</p> <p>This is a purely academic question, because <code>memmove</code> is provided together with the compiler. In practice, the compiler authors can simply promote undefined pointer comparison to unspecified behavior, or use the relevant pragma to force their compiler to compile their <code>memmove</code> correctly. For instance, <a href="http://www.student.cs.uwaterloo.ca/~cs350/common/os161-src-html/memmove_8c-source.html" rel="nofollow noreferrer">this implementation</a> has this snippet:</p> <pre><code>if ((uintptr_t)dst &lt; (uintptr_t)src) { /* * As author/maintainer of libc, take advantage of the * fact that we know memcpy copies forwards. */ return memcpy(dst, src, len); } </code></pre> <p>I would still like to use this example as proof that the standard goes too far with undefined behaviors, if it is true that <code>memmove</code> cannot be implemented efficiently in standard C. For instance, no-one ticked when answering <a href="https://stackoverflow.com/questions/3572309/memmove-implementation-in-c">this SO question</a>.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload