gcc size_t and sizeof arithmetic conversion to int

こ雲淡風輕ζ 提交于 2020-11-29 07:19:12

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!