【问题标题】:GCC, -O2, and bitfields - is this a bug or a feature?GCC、-O2 和位域 - 这是错误还是功能?
【发布时间】:2010-05-14 19:23:16
【问题描述】:

今天我在尝试位域时发现了令人震惊的行为。为了讨论和简单起见,这里有一个示例程序:

#include <stdio.h>

struct Node
{
  int a:16 __attribute__ ((packed));
  int b:16 __attribute__ ((packed));

  unsigned int c:27 __attribute__ ((packed));
  unsigned int d:3 __attribute__ ((packed));
  unsigned int e:2 __attribute__ ((packed));
};

int main (int argc, char *argv[])
{
  Node n;
  n.a = 12345;
  n.b = -23456;
  n.c = 0x7ffffff;
  n.d = 0x7;
  n.e = 0x3;

  printf("3-bit field cast to int: %d\n",(int)n.d);

  n.d++;  

  printf("3-bit field cast to int: %d\n",(int)n.d);
}

程序故意导致 3 位位域溢出。这是使用“g++ -O0”编译时的(正确)输出:

3 位字段转换为 int:7

3 位字段转换为 int:0

这是使用“g++ -O2”(和 -O3)编译时的输出:

3 位字段转换为 int:7

3 位字段转换为 int:8

检查后一个示例的程序集,我发现:

movl    $7, %esi
movl    $.LC1, %edi
xorl    %eax, %eax
call    printf
movl    $8, %esi
movl    $.LC1, %edi
xorl    %eax, %eax
call    printf
xorl    %eax, %eax
addq    $8, %rsp

优化刚刚插入“8”,假设 7+1=8,而实际上数字溢出并且为零。

幸运的是,据我所知,我关心的代码没有溢出,但这种情况让我感到害怕——这是一个已知的错误、一个功能,还是这是预期的行为?我什么时候可以期望 gcc 在这方面是正确的?

编辑(回复:已签名/未签名):

它被视为无符号,因为它被声明为无符号。将其声明为 int 你会得到输出(使用 O0):

3 位字段转换为 int:-1

3 位字段转换为 int:0

在这种情况下,使用 -O2 会发生更有趣的事情:

3 位字段转换为 int:7

3 位字段转换为 int:8

我承认 attribute 使用起来很可疑;在这种情况下,我担心的是优化设置的差异。

【问题讨论】:

  • chedcked gcc 4.4.1 - 输出为 7/0 有/无优化
  • 我承认我使用的是 4.1.2 - 感谢您的提醒。
  • 如果你把__attribute__((__packed__))放在整个结构之后会发生什么?

标签: c++ c gcc bit-fields optimization


【解决方案1】:

如果您想获得技术知识,那么在您使用 __attribute__(包含两个连续下划线的标识符)的那一刻,您的代码就有/有未定义的行为。

如果您在删除后得到相同的行为,在我看来它就像一个编译器错误。一个 3 位字段被视为 7 的事实意味着它被视为无符号,因此当您溢出时,它应该像任何其他无符号一样,并为您提供模运算。

将位字段视为已签名也是合法的。在这种情况下,第一个结果将是 -1-3-0(可能仅打印为 0),而第二个结果是未定义的(因为有符号整数的溢出会产生未定义的行为)。理论上,其他值在 C89 或当前 C++ 标准下可能是可能的,因为它们不限制有符号整数的表示。在 C99 或 C++0x 中,它只能是这三个(C99 将有符号整数限制为一个补码、二进制补码或符号幅度,而 C++0x 是基于 C99 而不是 C90)。

糟糕:我没有给予足够的关注——因为它被定义为unsigned,它必须被视为unsigned,几乎没有回旋余地来摆脱它作为编译器错误。

【讨论】:

  • 删除 attribute 也会导致 -O2 的行为不正确,但 O0 不会(根据原始代码)。看来我需要使用 gcc 4.4!
猜你喜欢
  • 2013-05-08
  • 2015-01-20
  • 2021-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-21
  • 2022-01-04
相关资源
最近更新 更多