评估/访问结构

时间:2013-12-03 04:57:26

标签: c gcc struct volatile

考虑相同代码的两个略有不同的版本:

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, %ebp
        andl    $-16, %esp
        call    ___main
        xorl    %eax, %eax
        leave
        ret

        .comm   _s, 64, 5

请注意在第二种情况下无法访问s

这是一个编译器错误还是我只是处理C标准的以下声明而gcc开发人员只是选择了这样一个奇怪的实现定义并且仍然按规则播放?:

  

对具有volatile限定类型的对象的访问构成是实现定义的。

造成这种差异的原因是什么?我自然希望整个结构被访问(或者不被访问,我不确定),无论其大小和内部结构如何。

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

1 个答案:

答案 0 :(得分:3)

这个问题的C和C ++之间存在差异,这解释了正在发生的事情。

铛-3.4

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

volatile.c:8:2: warning: expression result unused; assign into a variable to force a volatile load [-Wunused-volatile-lvalue] s;

在C99模式下编译时未发出这些警告。正如this blog postthis GCC wiki entry from the question comments中所述,在此上下文中使用s导致在C中进行左值到右值的转换,但在C ++中则不然。这是通过检查Clang AST for C来确认的,因为有一个来自LvalueToRValue的ImplicitCastExpr,它在从C ++生成的AST中不存在。 (AST不受结构大小的影响。)

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;更改为s.dummy;时,访问权限不会出现在任一版本中。我不熟悉gcc的内部结构,因为我和LLVM一样,所以我不能推测为什么会发生这种情况。但基于上述观察,我认为由于不一致,这是一个编译器错误。