采用以下示例:
typedef struct array_struct {
unsigned char* pointer;
size_t length;
} array;
typedef struct vector_struct {
unsigned char* pointer;
// Reserved is the amount of allocated memory not being used.
// MemoryLength = length + reserved;
size_t length, reserved;
} vector;
// Example Usage:
vector* vct = (vector*) calloc(sizeof(vector), 1);
vct->reserved = 0;
vct->length = 24;
vct->pointer = (unsigned char*) calloc(arr->length, 1);
array* arr = (array*) vct;
printf("%i", arr->length);
free(arr->pointer);
free(arr);
C似乎按照它们在struct中定义的顺序为struct成员分配内存。这意味着如果您投射vector -> array
,如果您在array
上执行操作,您仍会获得相同的结果,就像您在vector
上执行操作一样,因为他们拥有相同的成员和成员的顺序。
只要您从vector -> array
向下投射,好像array
是vector
的通用类型,就不应该遇到任何问题。
尽管类型结构相似,这是不确定和不良行为吗?
答案 0 :(得分:6)
这是明确定义的行为,如果您允许类型别名(C大多数编译器没有,默认情况下或通过某些编译标志),如果禁止这种类型的别名,则它是未定义的行为(通常被称为“严格别名”,因为规则非常严格。根据C标准的N1570草案:
6.5.2.3
6为了简化联合的使用,我们做了一个特别的保证:如果一个联合包含几个共享一个共同初始序列的结构(见下文),并且联合对象当前包含一个在这些结构中,允许检查其中任何一个的共同初始部分,可以看到完整类型的联合声明。 如果相应的成员具有一个或多个初始成员序列的兼容类型(对于位字段,宽度相同),则两个结构共享一个公共初始序列。
该部分是关于联合的,但为了使这种行为在联合中合法,它限制了填充的可能性,因此需要两个结构共享一个共同的布局和初始填充。所以我们已经为我们做了这件事。
现在,对于严格的别名,标准说:
6.5
7对象的存储值只能由具有以下类型之一的左值表达式访问:
- 与对象的有效类型兼容的类型
- [...]
“兼容类型”是:
6.2.7
1如果类型相同,则两种类型具有兼容类型。
它继续解释更多,并列出一些具有更多“摆动空间”的案例,但这些都不适用于此。不幸的是,降压在这里停止。这是未定义的行为。
现在,你可以做的一件事就是:
typedef struct array_struct {
unsigned char* pointer;
size_t length;
} array;
typedef struct vector_struct {
array array;
size_t reserved;
} vector;