微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

评估/访问结构

考虑相同代码的两个稍微不同的版本:
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,所以我不能猜测为什么会发生这种情况.但是基于上述观察结果,我会说这是一个由于不一致而导致的编译器错误.

原文地址:https://www.jb51.cc/c/112967.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐