C++ 为什么64位GCC在分配数组时警告将常量int转换为长无符号int?
我有一个文件test.cpp,如下所示:C++ 为什么64位GCC在分配数组时警告将常量int转换为长无符号int?,c++,arrays,gcc,64-bit,C++,Arrays,Gcc,64 Bit,我有一个文件test.cpp,如下所示: void f(const int n) { unsigned char *a=new unsigned char[n]; delete[] a; } int main() { f(4); return 0; } 使用-Wsign conversion标志在64位GCC中编译它会产生警告: test.cpp:2:39: warning: conversion to ‘long unsigned int’ from ‘const int’
void f(const int n) {
unsigned char *a=new unsigned char[n];
delete[] a;
}
int main() {
f(4);
return 0;
}
使用-Wsign conversion
标志在64位GCC中编译它会产生警告:
test.cpp:2:39: warning: conversion to ‘long unsigned int’ from ‘const int’ may change the sign of the result [-Wsign-conversion]
(第2行是调用new
的行)。在我看来,GCC在分配数组时发出这样的警告似乎很奇怪,但以下事情更奇怪:
unsigned char*a=新的unsigned char[(long unsigned int)n]替换有问题的行代码>不会消除警告,使用static\u cast()
也不会消除警告
void f(tn)
定义了f
,其中T
为
T
是任何小于64位的常量有符号整数类型时,它会产生警告
请记住,我在一台64位(Linux)机器上,为什么符号转换警告在这种情况下关心n
的常量和大小,为什么类型转换不能解决这个问题
注1:我想在另一个编译器下测试这一点,但Comeau网站已经关闭,我没有访问任何其他编译器的权限,因此我无法判断这是符合标准的行为,还是GCC错误
注释2:Test.CPP是一个从一个“真实”C++文件中的问题的最小例子,在其中我最好的方法是用“
”包围攻击线。const int是一个有符号值,您将有符号值强制转换为无符号值。
因此,编译器正在生成一个警告,在某些情况下,这种转换可能会导致错误的计算。好吧,它为您转换,但它警告您,它正在进行的转换将改变它正在改变的值的符号,否则您可能会自动丢失一些值,错误可能会导致它只是说您是 将int强制转换为无符号int这通常可能会更改符号的值,如果我将int传递给数组边界运算符,它不会像您这样发出警告
试着转动你打开的转换标志,看看它是否仍然这样做。该标志是导致警告的原因,因为它是进行转换的东西。我想,这与处理整数文本的方式有关:当你写
int myArray[10];
数字10被转换成有符号整数,编译器不应该因为明显的原因而抱怨这个数字。所以,我想,有符号整数的类型检查中会出现异常。当使用const int时,GCC似乎认为这是一个不适用整数异常的不同类型,因此警告: TL;DR:如果它代表某个东西的大小,那么将其设置为
std::size\u t
问题是数组
new
将类型为std::size\u t
的值作为其大小参数,该值由标准保证为无符号整数类型,编译器抱怨将其转换为长无符号int
就证明了这一点。这就是有符号-无符号转换发生的地方,(IMO)解决该问题的正确方法就是简单地给出函数f
typestd::size\u t
的参数n
。这至少在用于x86_64 GNU/Linux的GCC 4.6中会抑制警告。编译器会发出警告,因为在转换为无符号值时符号可能会更改
一,。用无符号字符替换有问题的行*a=新的无符号字符[(长无符号整数)n];不会消除警告,也不会使用static_cast()
符号转换的问题仍然存在,您只是将其显式化了。我的猜测是,它仍然不够明确,编译器不会相信你。它仍然相信您声明n
a signedconst int
是有原因的
二,。如果用签名void f(tn)定义f,则不会产生警告,其中T是
一,。任何大小的非常量、有符号或无符号整数类型
如果n
为非常量,则函数开头和转换之间可能存在代码,这确保了n为正,如n=(长无符号int)(n)代码>。在这种情况下,编译器似乎给了您怀疑的好处,因此没有发出警告。当它被声明为const时,编译器肯定知道它正在处理一个int
,并发出警告
我承认,我的解释听起来不像g++通常会做的事情。问题在于函数的签名-当您将常量literal 4传递给一个声明为常量int的函数时,编译器会进行隐式转换
您可以尝试将参数类型替换为const unsigned int,以消除警告消息。我对细节有点不太了解,但在我看来,问题实际上在于符号扩展(因为在您的系统中,size\u t很可能是一个无符号长字符)。考虑下面的代码:
#include <stdio.h>
void f(const int n) {
unsigned long int b = static_cast<long unsigned int>(n);
printf ("0x%llx == %lld\n", b, b);
}
int main() {
unsigned long int c = 1;
c <<= 31;
printf ("0x%llx == %lld \n", c, c);
f(c);
return 0;
}
请注意,我特意选择了一个表示负数的值作为int,而不是long。第一次打印实际上应该是0x0000000080000000。如果我选择一个简单的-1,它仍然会得到符号扩展到-1的长度,但这一个给出了完全不同的东西
当然,如果您显式地将其强制转换为未签名的,您也会得到一些其他的结果,但我的猜测是编译器更担心隐式转换(在本例中是向上转换为64位),您更可能会错过这些转换(“更多位可能会出什么问题?”)
另一个提示是,困扰我们的是上转换(如果不是,我很高兴听到另一个解释):
所以我们排除了函数参数传递应该受到责备的选项
现在,如果我可以的话
#include <stdio.h>
void f(const int n) {
unsigned long int b = static_cast<long unsigned int>(n);
printf ("0x%llx == %lld\n", b, b);
}
int main() {
unsigned long int c = 1;
c <<= 31;
printf ("0x%llx == %lld \n", c, c);
f(c);
return 0;
}
0x80000000 == 2147483648
0xffffffff80000000 == -2147483648
int main() {
int n = 1;
const long int a = static_cast<long int> (n);
const int b = static_cast<int> (n);
char* ap = new char [a];
char* bp = new char [b];
}
test.cpp: In function ?int main()?:
test.cpp:8:27: warning: conversion to ?long unsigned int? from ?const int? may change the sign of the result [-Wsign-conversion]
char* bp = new char [b];