结构成员的地址是否定义了行为?
Is address of structure members defined behavior?
有时我对结构进行指针运算,但我不确定它是否是已定义的行为..
如果我有这个结构
typedef struct SCustomData{
uint32_t a;
uint32_t b;
}CustomData;
有时对我来说,与其不断地输入结构的不同字段,不如给它一个恒定的大小并适合我需要的任何内容。
我的第一个问题是:结构的地址也是结构中第一个变量的地址是否定义了行为?
int main(){
CustomData cd = {0};
cd.a = 0xDEADBEEF;
uint32_t a = 0;
memcpy(&a,&cd,sizeof(uint32_t));
assert(a==0xDEADBEEF);
return 0;
}
那会永远成功吗?
我的下一个问题是,只要我知道每个成员的大小,我可以使用指针算法访问结构的任何成员吗?
int main(){
CustomData cd = {0};
cd.b = 0xABCD0000;
uint16_t highshort = *(uint16_t*)((uint8_t*)&cd+sizeof(uint32_t)+sizeof(uint16_t));
assert(highshort == 0xABCD);
uint8_t highbyte = *(uint8_t*)((uint8_t*)&cd+sizeof(uint32_t)+sizeof(uint16_t)+sizeof(uint8_t));
assert(highbyte == 0xAB);
return 0;
}
除了可能看起来丑陋或糟糕的代码实践之外,至少定义了行为?我应该避免它吗?
如果我不使用指针转换而是使用 memcpy,这仍然是个坏主意吗?
int main(){
CustomData cd = {0};
cd.b = 0xABCD0000;
uint16_t highshort = 0;
memcpy(&highshort, ((uint8_t*)&cd)+sizeof(uint32_t)+sizeof(uint16_t), sizeof(uint16_t));
assert(highshort == 0xABCD);
return 0;
}
第一个问题
它实际上是在C标准中定义的!第6.7.2.1
节(在此standard draft)
15 Within a structure object, the non-bit-field members and the units in which bit-fields
reside have addresses that increase in the order in which they are declared. A pointer to a
structure object, suitably converted, points to its initial member (or if that member is a
bit-field, then to the unit in which it resides), and vice versa. There may be unnamed
padding within a structure object, but not at its beginning.
第二个问题
没有按照标准定义(又是第6.7.2.1
节):
Each non-bit-field member of a structure or union object is aligned in an implementation-
defined manner appropriate to its type.
然而,大多数编译器以相同的方式对齐(per-architecture 和位数至少)
为什么它仍然是个坏主意
可维护性 - 如果您使用成员本身,您的代码将更容易维护。它不会依赖于编译器和位数,并且不会对代码中的更改敏感(例如更改类型或重新排序成员)。
可读性——你的意图当然会更加清晰。
-
有时我对结构进行指针运算,但我不确定它是否是已定义的行为..
如果我有这个结构
typedef struct SCustomData{
uint32_t a;
uint32_t b;
}CustomData;
有时对我来说,与其不断地输入结构的不同字段,不如给它一个恒定的大小并适合我需要的任何内容。
我的第一个问题是:结构的地址也是结构中第一个变量的地址是否定义了行为?
int main(){
CustomData cd = {0};
cd.a = 0xDEADBEEF;
uint32_t a = 0;
memcpy(&a,&cd,sizeof(uint32_t));
assert(a==0xDEADBEEF);
return 0;
}
那会永远成功吗?
我的下一个问题是,只要我知道每个成员的大小,我可以使用指针算法访问结构的任何成员吗?
int main(){
CustomData cd = {0};
cd.b = 0xABCD0000;
uint16_t highshort = *(uint16_t*)((uint8_t*)&cd+sizeof(uint32_t)+sizeof(uint16_t));
assert(highshort == 0xABCD);
uint8_t highbyte = *(uint8_t*)((uint8_t*)&cd+sizeof(uint32_t)+sizeof(uint16_t)+sizeof(uint8_t));
assert(highbyte == 0xAB);
return 0;
}
除了可能看起来丑陋或糟糕的代码实践之外,至少定义了行为?我应该避免它吗?
如果我不使用指针转换而是使用 memcpy,这仍然是个坏主意吗?
int main(){
CustomData cd = {0};
cd.b = 0xABCD0000;
uint16_t highshort = 0;
memcpy(&highshort, ((uint8_t*)&cd)+sizeof(uint32_t)+sizeof(uint16_t), sizeof(uint16_t));
assert(highshort == 0xABCD);
return 0;
}
第一个问题
它实际上是在C标准中定义的!第6.7.2.1
节(在此standard draft)
15 Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared. A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning.
第二个问题
没有按照标准定义(又是第6.7.2.1
节):
Each non-bit-field member of a structure or union object is aligned in an implementation- defined manner appropriate to its type.
然而,大多数编译器以相同的方式对齐(per-architecture 和位数至少)
为什么它仍然是个坏主意
可维护性 - 如果您使用成员本身,您的代码将更容易维护。它不会依赖于编译器和位数,并且不会对代码中的更改敏感(例如更改类型或重新排序成员)。
可读性——你的意图当然会更加清晰。