tipos organizacional modelos importancia ejemplos comportamiento caracteristicas autores c

organizacional - ¿Un tipo con 2 definiciones de comportamiento indefinido en C?



tipos de comportamiento organizacional (2)

Estoy usando este enfoque hasta ahora y funciona bien, sin ningún comportamiento indefinido

Supongo que quiere decir que el código que presenta muestra el comportamiento observable que espera en las circunstancias en las que lo ha probado, lo cual es muy diferente de estar sin un comportamiento indefinido. Ciertamente, el código como lo publicó originalmente tuvo un comportamiento indefinido como resultado de la aplicación del operador sizeof a una expresión de tipo void .

Pero primero, sizeof (void *) y sizeof (Point *) son siempre los mismos

C no garantiza eso, ni que las representaciones de esos tipos de punteros sean equivalentes. Sin embargo, puede convertir de forma segura un Point * en un void * y viceversa, donde "de forma segura" significa que el resultado se comparará igual al Point * original Point * .

Me gustaría usar este enfoque mostrando Point_p a lib.c como typedef Point* Point_p y a todos los demás archivos que no forman parte de la biblioteca como typedef void* Point_p .

Esto no es seguro y formalmente exhibiría un comportamiento indefinido, que podría o no manifestarse de una manera que usted note. Aunque puede convertir entre ellos, Point * y void * no son tipos "compatibles" en el sentido estándar del término.

Un mejor patrón para implementar tipos opacos en C es usar tipos incompletos . Eso se vería algo así:

lib.h:

// User header for lib #ifndef __LIB_H #define __LIB_H // Structure for a single point -- NO BODY DECLARED typedef struct point Point; // Create point Point *createPoint(int x, int y); #endif

lib.c:

#include <stdlib.h> #include "lib.h" // complete the definition of struct point struct point { int x, y; }; Point *createPoint(int x, int y) { Point *p = malloc(sizeof(*p)); p->x = x; p->y = y; return p; }

Con eso, no tiene macros desordenadas que controlen qué partes del encabezado se deben usar, y ni siquiera tiene que preocuparse por el código del cliente simplemente declarando __LIB_INTERNAL para obtener acceso a los miembros de la estructura, porque no están en el encabezado en absoluto . Sin embargo, todo esto tiene un comportamiento perfectamente definido y, además, una mejor seguridad de tipo que el uso de void * para todo.

Considera una biblioteca donde tengas algún código. Por ejemplo, hagamos algún punto X e Y manipulación.

Y luego construyes tu biblioteca donde no quieres permitir que los usuarios accedan a tu variable de estructura, hasta ahora estoy usando este enfoque y parece funcionar bien.

lib.h:

#ifndef __LIB_H #define __LIB_H #ifdef __LIB_INTERNAL //Structure for single point typedef struct { int x, y; } Point; //Casted pointer #define _P(in) ((Point *)(in)) #endif //Define pointer for public use as void pointer typedef void* Point_p; //Create point Point_p createPoint(int x, int y); #endif

lib.c:

//Define LIB_INTERNAL to allow visible access #define __LIB_INTERNAL #include "lib.h" #include "stdlib.h" Point_p createPoint(int x, int y) { Point_p p = malloc(sizeof(Point)); _P(p)->x = x; //_P is visible in this function _P(p)->y = y; return p; }

C Principal:

#include "lib.h" int main() { Point_p p = createPoint(1, 2); //OK Point *ptr = createPoint(1, 2); //Error as Point is not visible public p->x = 4; //Error as Point_p is void * }

De esta manera, me estoy asegurando de que el usuario no tenga acceso directo a la variable Punto y se vea obligado a usar funciones para realizar operaciones en este punto.

Ahora estoy pensando en otro enfoque. Pero primero, sizeof(void *) y sizeof(Point *) es siempre el mismo, así que me gustaría usar este enfoque mostrando Point_p a lib.c como typedef Point* Point_p y a todos los demás archivos que no forman parte de la biblioteca como typedef void* Point_p .

lib.h

#ifndef __LIB_H #define __LIB_H #ifdef __LIB_INTERNAL //Structure for single point typedef struct { int x, y; } Point; //Define pointer for private use as Point pointer typedef Point* Point_p; #else //Define pointer for public use as void pointer typedef void* Point_p; #endif //Create point Point_p createPoint(int x, int y); #endif

lib.c:

//Define LIB_INTERNAL to allow visible access #define __LIB_INTERNAL #include "lib.h" #include "stdlib.h" Point_p createPoint(int x, int y) { Point_p p = malloc(sizeof(Point)); p->x = x; //_P is not needed because Point_p is visible as Point * p->y = y; return p; }

main.c: igual que el anterior

Pregunta

¿Es este comportamiento indefinido? Debido a que, en segundo lugar, lib.c ve a Point_p como Point * , pero main.c todavía lo ve como void * y, por lib.c tanto, lib.c tiene acceso a los miembros directamente sin lanzar antes y main.c no lo tiene. la estructura esta oculta


Sí lo es. No se garantiza que los punteros Struct tengan la misma representación que los punteros nulos.

Sin embargo, se garantiza que todos los punteros de estructura tienen la misma representación independientemente de la etiqueta,

6.2.5p28 :

... Todos los punteros a los tipos de estructura deben tener los mismos requisitos de representación y alineación que los demás. Todos los punteros a los tipos de unión deben tener los mismos requisitos de representación y alineación que los demás. ...

por lo tanto, la forma común y bien definida de resolver esto es proporcionar solo una declaración hacia adelante de una estructura en el encabezado público y luego usar punteros para eso.

public_header.h

struct Point; //the private header provides the full definition struct Point* createPoint(int x, int y); //...

private_header:

#include "public_header.h" struct Point { int x, y; }; //full definition

Ese enfoque tampoco sufre de la holgura de tipo de los punteros de void .

(También debe evitar usar identificadores que comiencen con dos guiones bajos o un guión bajo y una letra mayúscula, así como identificadores / etiquetas de telescopios que comiencen con un guión bajo (nunca empiece los identificadores con un guión bajo si quiere que sea sencillo). comportamiento indefinido también (ver 7.1.3 identificadores reservados )).