我遇到了另一个线程中描述的类似问题(perf_event_open-如何监视多个事件)。我能够解决它,并且代码可以正常工作,但是我想了解为什么这部分实际上有效,以及如何不违反任何形式:
char buf[4096];
struct read_format* rf = (struct read_format*) buf;
struct read_format的定义如下:
struct read_format {
uint64_t nr;
struct {
uint64_t value;
uint64_t id;
} values[/*2*/]; };
编译器如何知道uint64_t nr
应将哪个值初始化?还是如何初始化内部结构呢?
此代码在标准C中不正确:
char buf[4096];
read(fd1, buf, 4096); // Assume error handling, omitted for brevity
struct read_format* rf = (struct read_format*) buf;
printf("%llu\n", rf->nr);
有两个问题-这些是不应该混为一谈的不同问题-:
buf
可能未正确对齐struct read_format
。如果不是,则行为是不确定的。rf->nr
违反严格的别名规则,并且行为未定义。类型char
为的表达式无法读取已声明类型的对象。unsigned long long
。注意相反的说法是不正确的。为什么看起来有效?好吧,“未定义”并不意味着“必须爆炸”。这意味着C标准不再指定程序的行为。这类代码在实际代码库中有些常见。到目前为止,主要的编译器供应商都包含逻辑,因此该代码将表现为“预期的”,否则会有太多人抱怨。
“预期的”行为是访问的*rf
行为应类似于struct read_format
在地址处存在一个对象,并且该对象的字节与的字节相同buf
。类似于两个人都在一个union
。
可以使代码符合联合:
union
{
char buf[4096];
struct read_format rf;
} u;
read(fd1, u.buf, sizeof u.buf);
printf("%llu\n", u.rf->nr);
对于通过名称访问的工会成员,严格的别名规则是“禁用”;由于联盟将对所有成员进行对齐,因此这也解决了对齐问题。
由您决定是否要遵从标准,还是相信编译器将继续在标准允许的限制范围内将实用性放在最大优化之上。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句