Fat*_*eep 6 c struct memory-address type-punning
请看以下示例:
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);
Run Code Online (Sandbox Code Playgroud)
C似乎按照它们在结构中定义的顺序为结构成员分配内存.这意味着如果你投射vector -> array你仍会得到相同的结果如果你执行操作array就像你做的那样,vector因为他们有相同的成员和成员的顺序.
只要你只下跌,从投vector -> array仿佛array是一个通用型的vector,你不应该遇到任何问题.
尽管类型结构相似,这是不确定和不良行为?
如果您允许类型别名(C大多数编译器没有,默认情况下或通过某些编译标志执行),这是明确定义的行为,如果禁止此类型的别名(通常引用),则它是未定义的行为作为"严格别名",因为规则非常严格).从N1570 C标准草案:
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;
Run Code Online (Sandbox Code Playgroud)