评估/访问结构

考虑相同代码的两个稍微不同的版本:
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开发人员只是选择了这样一个奇怪的实现定义,并且仍然遵循规则:

What constitutes an access to an object that has volatile-qualified type is implementation-defined.

这个差异的原因是什么?我自然会期望整个结构被访问(或不被访问,我不知道),不管其大小和内部的内容.

附:在这种情况下,您的编译器(非gcc或更新的gcc)是做什么的? (如果这是您要解决的唯一部分,请在评论中回答这个最后一个问题,因为这不是主要问题,更多是好奇的问题).

解决方法

这个问题的C和C之间有区别,这说明了发生了什么.

铛 – 3.4

当将这些片段中的任一个编译为C时,发出的程序集在任何情况下都不引用.实际上发出了两个警告:

volatile.c:8:2:warning:表达式结果未使用;分配给一个变量来强制易变负载[-Wunused-volatile-lvalue]
S;

在C99模式下编译时,不会发出这些警告.如this blog postthis 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,所以我不能猜测为什么会发生这种情况.但是基于上述观察结果,我会说这是一个由于不一致而导致的编译器错误.

相关文章

本程序的编译和运行环境如下(如果有运行方面的问题欢迎在评...
水了一学期的院选修,万万没想到期末考试还有比较硬核的编程...
补充一下,先前文章末尾给出的下载链接的完整代码含有部分C&...
思路如标题所说采用模N取余法,难点是这个除法过程如何实现。...
本篇博客有更新!!!更新后效果图如下: 文章末尾的完整代码...
刚开始学习模块化程序设计时,估计大家都被形参和实参搞迷糊...