Código 1:
unsigned int *p = malloc(sizeof *p); memset(p, 0x55, sizeof *p); unsigned int u = *p;Código 2:
void *d = malloc(50); *(double *)d = 1.23; memset(d, 0x55, 50); unsigned int u = *(unsigned int *)d; En cada caso, qué efecto tiene memset sobre el tipo efectivo del objeto en el espacio malloc'd; y entonces, ¿la u es correcta o es una violación estricta de alias?
La definición de tipo efectivo (C11 6.5/6) es:
El tipo efectivo de un objeto para acceder a su valor almacenado es el tipo declarado del objeto, si lo hay. Si un valor se almacena en un objeto que no tiene un tipo declarado a través de un lvalue que tiene un tipo que no es un tipo de carácter, entonces el tipo de lvalue se convierte en el tipo efectivo del objeto para ese acceso y para los accesos posteriores que no modifican el tipo. valor almacenado. Si un valor se copia en un objeto que no tiene un tipo declarado usando
memcpyomemmove, o se copia como una matriz de tipo de carácter, entonces el tipo efectivo del objeto modificado para ese acceso y para los accesos posteriores que no modifican el valor es el tipo efectivo del objeto del que se copia el valor, si lo tiene. Para todos los demás accesos a un objeto que no tiene un tipo declarado, el tipo efectivo del objeto es simplemente el tipo del lvalue utilizado para el acceso.
Sin embargo, no está claro si memset se comporta como escribir a través de un lvalue de tipo de carácter, o algo más. La descripción de memset (7.24.6.1) no es muy esclarecedora:
La función memset copia el valor de c (convertido en un
unsigned char) en cada uno de los primeros n caracteres del objeto señalado por s.
Mi 50ct:
Primero, divido esto en oraciones para una referencia más fácil:
La nota al pie podría ayudar aquí: "87) Los objetos asignados no tienen un tipo declarado". .
ADN: "no aplica"
Caso 1:
memset(...) : 1: DNA (sin tipo declarado), 2: DNA (memset escribe en char - semántica), 3: DNA (ni memcpy ni memmove), 4: char [] solo para memset internamente (no permanente ).unsigned int u = *p : 1: ADN (sin tipo declarado), 2/3: ADN (sin escritura, pero leído), 4: tipo de lvalue es unsigned int .Conclusión: no hay violación, pero la interpretación está definida por la implementación, ya que el valor real depende de la alineación dentro de la variable y la endianidad.
Caso 2:
*(double *)d = 1.23; : 2: d se convierte en double * para esta y las siguientes lecturas.memset(d, 0x55, 50); : igual que para el Caso 1.unsigned int u = *(unsigned int *)d : d sigue siendo double * : ¡bang! De cualquier manera, memset() es de poco uso para char que no sean caracteres, excepto si se usa 0 , que aún depende de la implementación , ya que ni (float)0.0 ni el puntero nulo necesitan ser realmente "todos los bits cero".
Por fin:
memset , ya que internamente, memset() copia por char: "... de c (convertido a un char sin firmar) en cada uno de los primeros n caracteres ..." (o usa char semántica, al menos ; la implementación real es irrelevante aquí).memset() , ya que solo se aplica a memcpy / memmove o cuando se copia como "una matriz de tipo de carácter". Lo cual tampoco lo hace (pero el primero sí, por lo que la condición or simplemente hace un bucle de copia explícito equivalente a las funciones).memset() no cambia el tipo efectivo del objeto. Eso difiere de memcpy y memmove . Eso resulta de la oración 4, que no incluye "... para ese acceso y para los accesos subsiguientes..." como dicen 2 y 3 y 1 implica.