问题
I decided to test compile a project with -Wsign-conversion enabled, to see what warnings would come up, and came across something that doesn't seem right, where gcc behaves differently than clang. Can someone please tell me which is correct?
I have a function that takes a size_t
param:
void func(size_t) {}
some other struct
struct Test {};
and calling code
int i = some_initialiser();
func(sizeof(Test) + static_cast<size_t>(i));
So from my understanding, sizeof
returns size_t
, and arithmetic between two variables of type size_t
should return a size_t
, so there shouldn't be any conversion here other than my static_cast
, but gcc gives me the warning
warning: conversion to ‘long unsigned int’ from ‘int’ may change the sign of the result [-Wsign-conversion]
Clang doesn't warn here, but does warn if I remove the static_cast
in the function call, as expected.
回答1:
This is a known bug in gcc, now fixed but not yet released.
The warning is valid (compilers can warn about anything they like), but gcc's behavior contradicts its own documentation. There is an existing bug report for this problem (see below).
Here's a simpler test case that illustrates the issue:
#include <cstddef>
int main() {
int i = 42;
size_t s0 = sizeof (int) + (size_t)i;
size_t s1 = sizeof (int) + static_cast<size_t>(i);
}
When I compile it on my system using gcc 9.1.0, I get:
$ g++ -Wsign-conversion -c c.cpp
c.cpp: In function ‘int main()’:
c.cpp:4:32: warning: conversion to ‘long unsigned int’ from ‘int’ may change the sign of the result [-Wsign-conversion]
4 | size_t s0 = sizeof (int) + (size_t)i;
| ^~~~~~~~~
c.cpp:5:32: warning: conversion to ‘long unsigned int’ from ‘int’ may change the sign of the result [-Wsign-conversion]
5 | size_t s1 = sizeof (int) + static_cast<size_t>(i);
| ^~~~~~~~~~~~~~~~~~~~~~
$
Note that the warning occurs both for a C-style cast and for a static_cast
.
It's true that the conversion may change the sign of the result (converting a negative int
to size_t
yields a positive result), but gcc's documentation for -Wsign-conversion
says:
'-Wsign-conversion'
Warn for implicit conversions that may change the sign of an
integer value, like assigning a signed integer expression to an
unsigned integer variable. An explicit cast silences the warning.
In C, this option is enabled also by '-Wconversion'.
In this case, an explicit cast is not silencing the warning.
This bug has already been reported:
Bug 87519 - -Wsign-conversion -Wconversion explicit cast fails to silence warning
I've added my test case and a link to this question and answer to the bug report.
A new comment from Marek Polacek on the bug report:
Fixed on trunk, will backport to 9.3 later.
The fix is commit 61e52125c935279af11b10d27060a96bff7477a4
in the gcc git repo, committed 2019-08-08.
回答2:
The warning is correct.
If i
has a negative value the casting will be problematic. Your function should return an unsigned value (e.g. unsigned int).
From GCC documentation - https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html:
For C++, also warn for confusing overload resolution for user-defined conversions; and conversions that never use a type conversion operator: conversions to
void
, the same type, a base class or a reference to them. Warnings about conversions between signed and unsigned integers are disabled by default in C++ unless-Wsign-conversion
is explicitly enabled.
来源:https://stackoverflow.com/questions/57403497/gcc-size-t-and-sizeof-arithmetic-conversion-to-int