评估/访问结构
考虑相同代码的两个稍微不同的版本:
struct s { int dummy[1]; }; volatile struct s s; int main(void) { s; return 0; } 和 struct s { int dummy[16]; }; volatile struct s s; int main(void) { s; return 0; } 以下是我使用gcc 4.6.2为他们: _main: pushl %ebp movl %esp,%ebp andl $-16,%esp call ___main movl _s,%eax xorl %eax,%eax leave ret .comm _s,4,2 和 _main: pushl %ebp movl %esp,%esp call ___main xorl %eax,64,5 请注意在第二种情况下无法访问s. 是否是编译器错误,或者我只是处理C标准的以下语句,gcc开发人员只是选择了这样一个奇怪的实现定义,并且仍然遵循规则:
这个差异的原因是什么?我自然会期望整个结构被访问(或不被访问,我不知道),不管其大小和内部的内容. 附:在这种情况下,您的编译器(非gcc或更新的gcc)是做什么的? (如果这是您要解决的唯一部分,请在评论中回答这个最后一个问题,因为这不是主要问题,更多是好奇的问题). 解决方法
这个问题的C和C之间有区别,这说明了发生了什么.
铛 – 3.4 当将这些片段中的任一个编译为C时,发出的程序集在任何情况下都不引用.实际上发出了两个警告: volatile.c:8:2:warning:表达式结果未使用;分配给一个变量来强制易变负载[-Wunused-volatile-lvalue] 在C99模式下编译时,不会发出这些警告.如this blog post和this GCC wiki entry from the question comments中所述,在这种情况下使用s会导致C中的lvalue-to-rvalue转换,而不是C中的.这通过检查C的Clang AST来确认,因为来自LvalueToRValue的ImplicitCastExpr在C中生成的AST中不存在. (AST不受struct的大小的影响). Clang源的快速grep揭示了在聚合表达式的排放中: case CK_LValueToRValue: // If we're loading from a volatile type,force the destination // into existence. if (E->getSubExpr()->getType().isVolatileQualified()) { EnsureDest(E->getType()); return Visit(E->getSubExpr()); } EnsureDest强制排放堆栈槽,大小和类型为表达式.由于优化器不允许删除易失性访问,它们分别保留在IR和输出asm中的标量加载/存储和memcpy.鉴于上述情况,这是我期望的行为. GCC-4.8.2 在这里,我观察到与问题相同的行为.但是当我改变表达式时,到s.dummy;访问不会出现在任一版本中.我不熟悉gcc的内部,因为我使用LLVM,所以我不能猜测为什么会发生这种情况.但是基于上述观察结果,我会说这是一个由于不一致而导致的编译器错误. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |