c++ - usos - punteros y vectores en c
Regla de alias estricta y punteros ''char*'' (3)
si tenemos dos punteros, uno de tipo
char *
y otro de tipostruct something *
apuntando a la misma ubicación, ¿cómo es posible que el primero alias el segundo y el segundo no sea el primero?
Lo hace, pero ese no es el punto.
El punto es que si tienes una o más struct something
entonces puedes usar un char*
para leer sus bytes constituyentes, pero si tienes una o más char
, entonces no puedes usar una struct something*
para leerlas.
La respuesta aceptada a ¿Cuál es la regla estricta de alias? menciona que puedes usar char *
para asignar un alias a otro tipo pero no a la inversa.
No tiene sentido para mí: si tenemos dos punteros, uno de tipo char *
y otro de tipo struct something *
apunta a la misma ubicación, ¿cómo es posible que el primer alias sea el segundo pero el segundo no lo haga? ¿el primero?
si tenemos dos punteros, uno de tipo
char *
y otro de tipostruct something *
apuntando a la misma ubicación, ¿cómo es posible que el primero alias el segundo y el segundo no sea el primero?
Los punteros no se alias unos a otros; eso es un uso descuidado del lenguaje. El aliasing es cuando se usa un lvalue para acceder a un objeto de un tipo diferente. (Desreferenciar un puntero da un valor l).
En su ejemplo, lo importante es el tipo de objeto alias. Para un ejemplo concreto, digamos que el objeto es un double
. Acceder al double
al eliminar la referencia de un char *
apunta al doble está bien porque la regla estricta de aliasing lo permite. Sin embargo, acceder a un double
mediante la desreferenciación de una struct something *
no está permitido (a menos que, posiblemente, ¡la estructura comience con el double
!).
Si el compilador está mirando una función que toma caracteres char *
y struct something *
, y no tiene disponible la información sobre el objeto al que se apunta (esto es realmente improbable, ya que los pases de aliasing se realizan en una etapa de optimización de todo el programa); entonces tendría que tener en cuenta la posibilidad de que el objeto pudiera ser realmente una struct something *
, por lo que no se podría realizar una optimización dentro de esta función.
La redacción en la respuesta a la que se hace referencia es un poco errónea, así que solucionemos primero: un objeto nunca alias a otro objeto , pero dos punteros pueden "alias" al mismo objeto (es decir, los punteros apuntan a la misma ubicación de memoria, como MM apuntó fuera, esta todavía no es una redacción correcta al 100%, pero obtienes la Idea). Además, el estándar en sí mismo (según mi conocimiento) en realidad habla de un alias estricto, pero solo da reglas, a través de qué tipo de expresiones se puede acceder o no a un objeto. Las marcas de compilación como ''-fno-strict-aliasing'' le dicen al compilador si puede asumir que el programador siguió esas reglas (para que pueda realizar optimizaciones basadas en esa suposición) o no.
Ahora a su pregunta: se puede acceder a cualquier objeto a través de un puntero a char
, pero no se puede acceder a un objeto char
(especialmente a una matriz de caracteres) a través de la mayoría de los otros tipos de punteros. En base a eso, el compilador puede / debe hacer las siguientes suposiciones:
- Si el tipo del objeto real en sí mismo no se conoce, un
char*
yT*
siempre podrían apuntar al mismo objeto (alias entre sí) -> relación simétrica. - Si
T1
yT2
no están "relacionados" y no sonchar
, entoncesT1*
yT2*
nunca pueden apuntar al mismo objeto -> relación simétrica - Un
char*
puede apuntar a unchar
O a un objetoT
- A
T*
NO puede apuntar a un objetochar
-> una relación simétrica
Creo que la razón principal detrás de las reglas asimétricas sobre el acceso a objetos a través de punteros es que una matriz de caracteres podría no satisfacer los requisitos de alineación de, por ejemplo, un int
.
Por lo tanto, incluso sin las optimizaciones del compilador basadas en la regla estricta de aliasing, por ejemplo, escribir un int
en la ubicación de una matriz de caracteres de 4 bytes en las direcciones 0x1,0x2,0x3,0x4 dará como resultado, en el mejor de los casos, un rendimiento deficiente y - en en el peor de los casos: acceda a una ubicación de memoria diferente, ya que las instrucciones de la CPU pueden ignorar los dos bits de dirección más bajos al escribir un valor de 4 bytes (por lo que aquí puede resultar en una escritura a 0x0,0x1,0x2 y 0x3).
Tenga en cuenta que el significado de "relacionado" difiere de un idioma a otro (entre C y C ++), pero eso no es relevante para su pregunta.