为什么g++ 4.8.1会发出转换警告?

4

当我用g++ 4.8.1(64位)以以下方式编译下面的代码时:

$ g++ -Wconversion -o main main.cpp

我得到了这个结果:
main.cpp: In function ‘int main()’:
main.cpp:12:20: warning: conversion to ‘int’ from ‘long unsigned int’ may alter its value [-Wconversion]
   int i = sizeof(x)/sizeof(x[0]);
                    ^

我希望编译器能够在编译时计算表达式的值。如果你用普通的 C 语言编写类似的程序,gcc 可以很好地工作。

这是否应该被认为是 g++ 的一个 bug(例如,clang++ 没有这个问题)?

如果你把有问题的那一行改成类似这样的代码:

char c = 0x10000000/0x1000000;

如果编译器没有抱怨,则说明在生成警告之前进行了某些常量评估。

main.cpp:

#include <iostream>

struct foo {
  int a;
  int b;
};

foo x[50];

int main()
{
  int i = sizeof(x)/sizeof(x[0]);
  std::cout << i << std::endl;

  return 0;
}

只是没有优化吗?尝试使用“-O2”选项,它应该在编译时进行评估。 - Rup
我在4.8版本中也收到了警告,但在即将发布的4.9版本中(大约一周前的GCC源代码)没有收到警告,因此我认为GCC开发人员认为这是一个错误,并已经修复了它。 - user743382
2个回答

7
 int i = sizeof(x)/sizeof(x[0]);
 //int <-- std::size_t <-- std::size_t / std::size_t

sizeof(x)/sizeof(x[0])表达式的类型是std::size_t,在你的机器上是unsigned long int。因此,如果源比目标大,则从此类型转换为int会丢失数据。

尽管如此,我认为在您的情况下,如果编译器实际计算该值,则不会出现实际数据丢失,但我猜测它在实际计算之前应用-Wconversion


1
除法是问题的原因,因为它是将该操作的结果转换为int的部分。除法本身是安全的。 - Fred Foo
1
有人能提供一个标准引用,说明在编译时评估表达式可以忽略标准中的其他规则吗?我只能找到一条注释,说浮点运算可以给出不同的结果,因为浮点精度没有指定。为什么这个问题中的转换不受标准转换规则的约束呢? - Joseph Mansfield
2
@sftrabbit:我的意思是,右手边的值不能溢出int,因为它的值最终为40(数组的大小),这是编译时常量。因此,即使从类型角度来看警告是有意义的,但从实际值的角度来看是多余的(编译器已知)。 - Nawaz
1
@Nawaz 哦,那很有道理。好观点。不过我一直看到有关编译时评估在某些规则方面豁免的建议。 - Joseph Mansfield
1
很可能只是编译器警告触发器不够复杂,会在任何无符号转换为有符号的情况下产生警告,因为它可能会产生问题(即使在这里明显不是问题)。 - Damon
显示剩余2条评论

0

sizeof() 返回的是 std::size_t 而不是 int!所以要进行强制类型转换或将 i 声明为 std::size_t

 std::size_t i = sizeof(x)/sizeof(x[0]);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接