c sockets strict-aliasing

¿Cuándo es seguro*para el alias de puntero estricto?



sockets strict-aliasing (2)

Correcto, el segundo ejemplo infringe las reglas de aliasing estrictas, por lo que si compila con el -fstrict-aliasing , existe la posibilidad de que obtenga un código de objeto incorrecto. La solución completamente correcta sería usar una unión aquí:

union { SocketMsgToRecv msg; char msgBuff[100]; }; recv(socket, msgBuff, 100); printf("Got Msg: a: %i, b: %i", msg.a, msg.b);

He estado tratando de entender las reglas de aliasing estrictas que se aplican al puntero del char.

Here se dice esto:

Siempre se supone que un char * puede referirse a un alias de cualquier objeto.

Ok, entonces en el contexto del código de socket, puedo hacer esto:

struct SocketMsg { int a; int b; }; int main(int argc, char** argv) { // Some code... SocketMsg msgToSend; msgToSend.a = 0; msgToSend.b = 1; send(socket, (char*)(&msgToSend), sizeof(msgToSend); };

Pero luego está esta declaración

Lo contrario no es verdad. Lanzar un char * a un puntero de cualquier tipo que no sea char * y quitarle la referencia por lo general infringe la regla de aliasing estricta.

¿Esto significa que cuando recvé una matriz de caracteres, no puedo reinterpretar el molde a una estructura cuando conozco la estructura del mensaje?

struct SocketMsgToRecv { int a; int b; }; int main() { SocketMsgToRecv* pointerToMsg; char msgBuff[100]; ... recv(socket, msgBuff, 100); // Ommiting make sure we have a complete message from the stream // but lets assume msgBuff[0] has a complete msg, and lets interpret the msg // SAFE!?!?!? pointerToMsg = &msgBuff[0]; printf("Got Msg: a: %i, b: %i", pointerToMsg->a, pointerToMsg->b); }

¿Este segundo ejemplo no funcionará porque el tipo de base es una matriz de caracteres y la estoy convirtiendo en una estructura? ¿Cómo manejas esta situación en un mundo estrictamente alias?


Re @ Adam Rosenfield: La unión logrará la alineación siempre y cuando el proveedor del char * comience a hacer algo similar.

Puede ser útil retroceder y descubrir de qué se trata todo esto.

La base para la regla de alias es el hecho de que los compiladores pueden colocar valores de diferentes tipos simples en diferentes límites de memoria para mejorar el acceso y que el hardware en algunos casos puede requerir dicha alineación para poder usar el puntero. Esto también puede aparecer en estructuras donde hay una variedad de elementos de diferentes tamaños. La estructura puede comenzar en un buen límite. Además, el compilador aún puede introducir mordiscos flojos en el interior de la estructura para lograr una alineación adecuada de los elementos estructurales que lo requieren.

Teniendo en cuenta que los compiladores a menudo tienen opciones para controlar cómo se maneja todo esto, o no, puede ver que hay muchas formas en que pueden ocurrir sorpresas. Esto es especialmente importante para tener en cuenta al pasar punteros a estructuras (emitidas como char * o no) en bibliotecas compiladas para esperar diferentes convenciones de alineación.

¿Qué hay de char *?

La presunción sobre char * es esa sizeof (char) == 1 (relativa a los tamaños de todos los demás datos considerables) y que los caracteres char * no tienen ningún requisito de alineación. Por lo tanto, un char * genuino siempre se puede pasar con seguridad y usar con éxito sin preocuparse por la alineación, y eso vale para cualquier elemento de una matriz char [], ejecutando ++ y - en los punteros, y así sucesivamente. (Curiosamente, el vacío * no es lo mismo).

Ahora debería ser capaz de ver cómo si transfiere algún tipo de datos de estructura en una matriz char [] que no estaba alineada correctamente, intentar volver a un puntero que requiere alineación (es) puede ser un problema grave.

Si realiza una unión de una matriz char [] y una estructura, la alineación más exigente (es decir, la de la estructura) será respetada por el compilador. Esto funcionará si el proveedor y el consumidor están utilizando efectivamente uniones que coincidan para que la conversión de struct * a char * y viceversa funcione bien.

En ese caso, espero que la información se haya creado en una unión similar antes de que el puntero se haya convertido a char * o se haya transferido de otra forma como una matriz de tamaño de bytes (char). También es importante asegurarse de que las opciones del compilador sean compatibles entre las bibliotecas en las que se basa y su propio código.