为什么64位GCC在分配数组时警告要将const int类型转换为长无符号int类型?

时间:2022-09-01 11:24:15

I have a file test.cpp that looks like this:

我有一个文件测试。cpp是这样的:

void f(const int n) {
  unsigned char *a=new unsigned char[n];
  delete[] a;
}

int main() {
  f(4);
  return 0;
}

Compiling it in 64-bit GCC with the -Wsign-conversion flag produces the warning:

使用-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]

(line 2 is the line in which new is called). It seems strange to me that GCC should give this warning about allocating an array, but the following things are even stranger:

(第2行是调用new的行)。对我来说,GCC发出关于分配数组的警告似乎有些奇怪,但下面的事情更奇怪:

  1. Replacing the offending line with unsigned char *a=new unsigned char[(long unsigned int)n]; does not get rid of the warning, nor does using static_cast<long unsigned int>().
  2. 用无符号char *a=新的无符号char[(long unsigned int)n]替换违规行;不删除警告,也不使用static_cast ()。
  3. No warning is produced if f is defined with the signature void f(T n), where T is

    如果f定义为带签名的void f(T n),则不产生任何警告,其中T为

    1. any non-const, signed or unsigned integer type of any size, or
    2. 任何大小的任何非const、有符号或无符号整数类型,或
    3. a signed 64-bit integer type.
    4. 一个带符号的64位整数类型。

    It does however produce warnings when T is any const signed integer type smaller than 64-bits.

    但是,当T是小于64位的任何委托整数类型时,它会产生警告。

Bearing in mind that I'm on a 64-bit (Linux) machine, why does the sign-conversion warning care about the constness and size of n in this case, and why doesn't type casting fix the problem?

考虑到我是在一台64位(Linux)机器上,为什么在这种情况下,信号转换警告会关心n的大小和一致性,为什么类型转换不能解决这个问题?

Note 1: I wanted to test this under another compiler, but the Comeau site is down, and I don't have access to any other compilers, so I can't tell if this is standard-compliant behaviour, or a GCC bug.

注意1:我想在另一个编译器下测试这个,但是这个网站已经关闭了,而且我无法访问任何其他编译器,所以我无法判断这是符合标准的行为,还是GCC bug。

Note 2: test.cpp is a minimal example of a problem from a "real" C++ file that I have in which the best way for me to get rid of the warning was to surround the offending line with:

注2:测试。cpp是我拥有的“真实”c++文件中出现的问题的一个最小的例子,在该文件中,我摆脱警告的最佳方法是用以下语句包围违规行:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-conversion"
// ...
#pragma GCC diagnostic pop

7 个解决方案

#1


1  

I'm a little flaky on the details, but it seems to me that the issue is actually in sign extension (since size_t is most likely an unsigned long on your system). Consider the following code:

我在细节上有点不太清楚,但在我看来,问题实际上是在符号扩展(因为size_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;
}

it prints:

它打印:

0x80000000 == 2147483648
0xffffffff80000000 == -2147483648

Note that I intentionally picked a value that means a negative as an int, but not as a long. The first print should actually be 0x0000000080000000. If I picked a simple -1, it would still get sign-extended to long as a -1, but this one gives something completely different.

注意,我故意选择了一个值,这个值表示负整数,而不是长整数。第一个输出应该是0x0000000080000000。如果我选择一个简单的-1,它仍然会得到-延伸到-1,但是这个会给出完全不同的结果。

Of course if you explicitly cast it to an unsigned you also get something else, but my guess is that the compiler is more worried about the implicit conversions (the up-convert to 64bit in this case) that you're more likely to miss ("what could possibly go wrong with more bits?")

当然,如果显式地将它转换为无符号,也会得到一些其他的东西,但是我猜想编译器更担心隐式转换(在本例中,向上转换为64位),您更可能会漏掉(“更多的位可能会出错吗?”)

Another hint it's the upconvert that's bugging us (if not, i'll be happy to hear another explanation):

另一个提示是,是向上的转化在困扰我们(如果不是,我很乐意听到另一个解释):

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];
}

This complains only on b

这只对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];

so we've ruled out the option that function arguments passing is to blame

所以我们排除了函数参数传递的选项。

Now, if I may further speculate, perhaps that warning is specific to memory allocations (note that you don't get it from simply casting n to long), because the compiler would have wanted to do some allocation magic given a constant size. Imagine the shock it got when it saw what you're trying to do.

现在,如果我可以进一步推测,也许这个警告是特定于内存分配的(注意,您并没有从简单的n到long中获得它),因为编译器想要做一些分配的魔法,给定一个常数大小。想象一下当它看到你想要做的事情时的震惊。

#2


0  

const int is a signed value, You are casting a signed value to unsigned value. So the compiler is generating a warning that in some cases, this conversion might result in wrong calculations.

const int是一个带符号值,您将一个带符号值转换为无符号值。因此编译器发出警告,在某些情况下,这种转换可能导致错误的计算。

#3


0  

well its converting for you but its warning you that the conversion it is making will change the sign of the value it is changing otherwise you might automatically lose some Value and bugs could resulytt its just saying you are casting a int to a unsigned int this may change the value of the sign normally if i passed int to the array bounds operator it would not warn like you like this

它转换为你但它警告你,转换是将改变值的符号它自动改变,否则你可能会失去一些价值和缺陷可能resulytt只是说你是铸造一个int unsigned int这可能改变符号的值通常如果我传递int数组边界算子不会警告说像你这样的

try tururning of the conversion flag that you have on and see if it still does this the flag is whats causing the warning because it is the thing doing the conversion

试着改变你所使用的转换标志,看看它是否仍然这样做,这个标志是引起警告的原因,因为它是执行转换的东西

#4


0  

I guess, this will have to do with the way integer literals are handled: When you write

我猜,这将与处理整型文字的方式有关:当你写的时候

int myArray[10];

the number ten is converted to a signed integer, and the compiler should never complain on that for obvious reasons. So, I guess, there will be an exception in the type checking for the signed integer. When you use a const int, gcc seems to consider this a different type for which the integer exception does not apply, hence the warning.

数字10被转换为一个有符号整数,编译器不应该因为明显的原因而对此抱怨。所以,我想,对于有符号整数,类型检查中会有一个异常。当您使用const int时,gcc似乎认为这是一个不适用整数异常的不同类型,因此警告。

#5


0  

The TL;DR: if it represents the size of something, make it a std::size_t.

TL;DR:如果它表示某物的大小,请将其设置为std: size_t。

The problem is that array new takes as its size parameter a value of type std::size_t, which is guaranteed by the standard to be an unsigned integral type, as evidenced by the compiler’s complaint of conversion to long unsigned int. That’s where the signed-unsigned conversion is taking place, and the (IMO) correct way to fix the problem is simply to give the parameter n of function f type std::size_t. This suppresses the warning at least with GCC 4.6 for x86_64 GNU/Linux.

问题是新需要作为它的大小参数数组的值类型std::size_t,保证的标准是一个无符号整型,就是明证编译器的抱怨长无符号整型的转换。这就是signed-unsigned转换发生,和(IMO)正确的解决这个问题的方法是给函数的参数n型std::size_t。这至少抑制了对x86_64 GNU/Linux的GCC 4.6的警告。

#6


0  

The compiler warns, because the sign might change when converting to an unsigned value.

编译器警告,因为符号在转换为无符号值时可能会发生变化。

1 . Replacing the offending line with unsigned char *a=new unsigned char[(long unsigned int)n]; does not get rid of the warning, nor does using static_cast().

1。用无符号char *a=新的无符号char[(long unsigned int)n]替换违规行;不删除警告,也不使用static_cast()。

The problem of sign conversion persists, you just made it explicit. My guess is, that it's still not explicit enough for the compiler to believe you. It still believes you declared n a signed const int for a reason!

符号转换的问题仍然存在,您只是使它变得显式。我的猜测是,它仍然不够明确,编译器不会相信你。它仍然相信你声明n为一个签名的常量int !

2 . No warning is produced if f is defined with the signature void f(T n), where T is

2。如果f定义为带签名的void f(T n),则不产生任何警告,其中T为

1 . any non-const, signed or unsigned integer type of any size

1。任何非const、已签名或无符号整数类型。

If n is non-const, there might be code between the beginning of the function and the conversion, that ensured that n was positive, like n = (long unsigned int)(n);. It seems that the compiler is giving you the benefit of doubt in this case, and therefore doesn't warn. When it is declared const, the compiler knows for sure that it is dealing with an int and warns.

如果n不是const,那么在函数的开始和转换之间可能有代码,确保n是正数,比如n =(长无符号int)(n);在这种情况下,编译器似乎给了您怀疑的好处,因此不会发出警告。当它被声明为const时,编译器肯定知道它正在处理int并发出警告。

I admit, my explanations don't sound like something g++ would typically do.

我承认,我的解释听起来不像是g++通常会做的事情。

#7


0  

The problem lies in the signature of your function - the compiler would do implicit conversion when you pass the constant literal 4 to a function with corresponding argument declared as const int.

问题在于函数的签名—当您将常量文字4传递给具有声明为const int的相应参数的函数时,编译器将执行隐式转换。

You can try replacing the argument type as const unsigned int to get rid of the warning message.

您可以尝试将参数类型替换为const unsigned int,以消除警告消息。

#1


1  

I'm a little flaky on the details, but it seems to me that the issue is actually in sign extension (since size_t is most likely an unsigned long on your system). Consider the following code:

我在细节上有点不太清楚,但在我看来,问题实际上是在符号扩展(因为size_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;
}

it prints:

它打印:

0x80000000 == 2147483648
0xffffffff80000000 == -2147483648

Note that I intentionally picked a value that means a negative as an int, but not as a long. The first print should actually be 0x0000000080000000. If I picked a simple -1, it would still get sign-extended to long as a -1, but this one gives something completely different.

注意,我故意选择了一个值,这个值表示负整数,而不是长整数。第一个输出应该是0x0000000080000000。如果我选择一个简单的-1,它仍然会得到-延伸到-1,但是这个会给出完全不同的结果。

Of course if you explicitly cast it to an unsigned you also get something else, but my guess is that the compiler is more worried about the implicit conversions (the up-convert to 64bit in this case) that you're more likely to miss ("what could possibly go wrong with more bits?")

当然,如果显式地将它转换为无符号,也会得到一些其他的东西,但是我猜想编译器更担心隐式转换(在本例中,向上转换为64位),您更可能会漏掉(“更多的位可能会出错吗?”)

Another hint it's the upconvert that's bugging us (if not, i'll be happy to hear another explanation):

另一个提示是,是向上的转化在困扰我们(如果不是,我很乐意听到另一个解释):

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];
}

This complains only on b

这只对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];

so we've ruled out the option that function arguments passing is to blame

所以我们排除了函数参数传递的选项。

Now, if I may further speculate, perhaps that warning is specific to memory allocations (note that you don't get it from simply casting n to long), because the compiler would have wanted to do some allocation magic given a constant size. Imagine the shock it got when it saw what you're trying to do.

现在,如果我可以进一步推测,也许这个警告是特定于内存分配的(注意,您并没有从简单的n到long中获得它),因为编译器想要做一些分配的魔法,给定一个常数大小。想象一下当它看到你想要做的事情时的震惊。

#2


0  

const int is a signed value, You are casting a signed value to unsigned value. So the compiler is generating a warning that in some cases, this conversion might result in wrong calculations.

const int是一个带符号值,您将一个带符号值转换为无符号值。因此编译器发出警告,在某些情况下,这种转换可能导致错误的计算。

#3


0  

well its converting for you but its warning you that the conversion it is making will change the sign of the value it is changing otherwise you might automatically lose some Value and bugs could resulytt its just saying you are casting a int to a unsigned int this may change the value of the sign normally if i passed int to the array bounds operator it would not warn like you like this

它转换为你但它警告你,转换是将改变值的符号它自动改变,否则你可能会失去一些价值和缺陷可能resulytt只是说你是铸造一个int unsigned int这可能改变符号的值通常如果我传递int数组边界算子不会警告说像你这样的

try tururning of the conversion flag that you have on and see if it still does this the flag is whats causing the warning because it is the thing doing the conversion

试着改变你所使用的转换标志,看看它是否仍然这样做,这个标志是引起警告的原因,因为它是执行转换的东西

#4


0  

I guess, this will have to do with the way integer literals are handled: When you write

我猜,这将与处理整型文字的方式有关:当你写的时候

int myArray[10];

the number ten is converted to a signed integer, and the compiler should never complain on that for obvious reasons. So, I guess, there will be an exception in the type checking for the signed integer. When you use a const int, gcc seems to consider this a different type for which the integer exception does not apply, hence the warning.

数字10被转换为一个有符号整数,编译器不应该因为明显的原因而对此抱怨。所以,我想,对于有符号整数,类型检查中会有一个异常。当您使用const int时,gcc似乎认为这是一个不适用整数异常的不同类型,因此警告。

#5


0  

The TL;DR: if it represents the size of something, make it a std::size_t.

TL;DR:如果它表示某物的大小,请将其设置为std: size_t。

The problem is that array new takes as its size parameter a value of type std::size_t, which is guaranteed by the standard to be an unsigned integral type, as evidenced by the compiler’s complaint of conversion to long unsigned int. That’s where the signed-unsigned conversion is taking place, and the (IMO) correct way to fix the problem is simply to give the parameter n of function f type std::size_t. This suppresses the warning at least with GCC 4.6 for x86_64 GNU/Linux.

问题是新需要作为它的大小参数数组的值类型std::size_t,保证的标准是一个无符号整型,就是明证编译器的抱怨长无符号整型的转换。这就是signed-unsigned转换发生,和(IMO)正确的解决这个问题的方法是给函数的参数n型std::size_t。这至少抑制了对x86_64 GNU/Linux的GCC 4.6的警告。

#6


0  

The compiler warns, because the sign might change when converting to an unsigned value.

编译器警告,因为符号在转换为无符号值时可能会发生变化。

1 . Replacing the offending line with unsigned char *a=new unsigned char[(long unsigned int)n]; does not get rid of the warning, nor does using static_cast().

1。用无符号char *a=新的无符号char[(long unsigned int)n]替换违规行;不删除警告,也不使用static_cast()。

The problem of sign conversion persists, you just made it explicit. My guess is, that it's still not explicit enough for the compiler to believe you. It still believes you declared n a signed const int for a reason!

符号转换的问题仍然存在,您只是使它变得显式。我的猜测是,它仍然不够明确,编译器不会相信你。它仍然相信你声明n为一个签名的常量int !

2 . No warning is produced if f is defined with the signature void f(T n), where T is

2。如果f定义为带签名的void f(T n),则不产生任何警告,其中T为

1 . any non-const, signed or unsigned integer type of any size

1。任何非const、已签名或无符号整数类型。

If n is non-const, there might be code between the beginning of the function and the conversion, that ensured that n was positive, like n = (long unsigned int)(n);. It seems that the compiler is giving you the benefit of doubt in this case, and therefore doesn't warn. When it is declared const, the compiler knows for sure that it is dealing with an int and warns.

如果n不是const,那么在函数的开始和转换之间可能有代码,确保n是正数,比如n =(长无符号int)(n);在这种情况下,编译器似乎给了您怀疑的好处,因此不会发出警告。当它被声明为const时,编译器肯定知道它正在处理int并发出警告。

I admit, my explanations don't sound like something g++ would typically do.

我承认,我的解释听起来不像是g++通常会做的事情。

#7


0  

The problem lies in the signature of your function - the compiler would do implicit conversion when you pass the constant literal 4 to a function with corresponding argument declared as const int.

问题在于函数的签名—当您将常量文字4传递给具有声明为const int的相应参数的函数时,编译器将执行隐式转换。

You can try replacing the argument type as const unsigned int to get rid of the warning message.

您可以尝试将参数类型替换为const unsigned int,以消除警告消息。