¿memcpy(&a + 1, &b + 1, 0) está definido en C11?


Esta pregunta sigue a esta pregunta anterior sobre la definición de memcpy(0, 0, 0), que se ha determinado concluyentemente que es un comportamiento indefinido.

Como muestra la pregunta vinculada, la respuesta depende del contenido de la cláusula 7.1.4:1 de C11

Cada una de las siguientes instrucciones se aplica a menos que se indique explícitamente lo contrario en las descripciones detalladas que siguen: Si un argumento a una función tiene un valor no válido (como un valor fuera del dominio del función, o un puntero fuera del espacio de direcciones del programa, o un puntero nulo, []]) [the] el comportamiento es indefinido. […]

La función estándar memcpy() espera punteros a void y const void, así:

void *memcpy(void * restrict s1, const void * restrict s2, size_t n);

La pregunta vale la pena hacerse en absoluto solo porque hay dos nociones de punteros "válidos" en el estándar: hay punteros que pueden obtenerse válidamente a través de la aritmética de punteros y pueden compararse válidamente con <, > a otros punteros dentro el mismo objeto. Y hay punteros que son válidos para desreferenciar. La primera clase incluye punteros "one-past" como &a + 1 y &b + 1 en el siguiente fragmento, mientras que la segunda clase no los incluye como válidos.

char a;
const char b = '7';
memcpy(&a + 1, &b + 1, 0);

Si el fragmento anterior se considera un comportamiento definido, a la luz del hecho de que los argumentos de memcpy() se escriben como punteros a void de todos modos, por lo que la cuestión de sus respectivas valididades no puede ser sobre desreferenciarlos. O debería &a + 1 y &b + 1 ser considerado "fuera del espacio de direcciones del programa"?

Esto me importa porque estoy en el proceso de formalizar los efectos de las funciones C estándar. Había escrito una condición previa de memcpy() como requires \valid(s1+(0 .. n-1));, hasta que se me señaló que GCC 4.9 había comenzado a agresivamenteoptimizar tales llamadas a funciones de biblioteca más allá de lo expresado en la fórmula anterior ( de hecho). La fórmula \valid(s1+(0 .. n-1)) en este lenguaje de especificación particular es equivalente a true cuando n es 0, y no captura el comportamiento indefinido en el que se basa GCC 4.9 para optimizar.

Author: Community, 2014-08-19

2 answers

C11 dice:

(C11, 7.24.2.1p2) "La función memcpy copia n caracteres del objeto apuntado por s2 en el objeto apuntado por s1."

&a + 1 en sí mismo es un puntero válido a la suma de enteros, pero &a + 1 no es un puntero a un objeto, por lo que la llamada invoca un comportamiento indefinido.

 18
Author: ouah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-19 18:39:45

Mientras que la respuesta" correcta " según el estándar parece estar en desacuerdo, solo puedo encontrar falso que después de int a [6]; int b [6]; todos

memcpy(a+0, b+0, 6);
memcpy(a+1, b+1, 5);
memcpy(a+2, b+2, 4);
memcpy(a+3, b+3, 3);
memcpy(a+4, b+4, 2);
memcpy(a+5, b+5, 1);

Debe ser válido (y copiar un área que termina al final de los arrays) mientras que

memcpy(a+6, b+6, 0);

Es válido a la luz del recuento pero no de las direcciones. ¡Es el mismo extremo del área copiada!

Personalmente, me inclinaría hacia la definición de memcpy (0,0,0) siendo válido también (con la justificación de solo exigir punteros válidos, pero sin objetos), pero al menos es un caso singular, mientras que el caso" fin de matriz " es una excepción real a un patrón regular para copiar un área al final de una matriz.

 5
Author: user3958062,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-19 21:47:26