Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

gcc size_t and sizeof arithmetic conversion to int

Tags:

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.

like image 832
John Ilacqua Avatar asked Aug 07 '19 23:08

John Ilacqua


People also ask

Can you use Size_t as an int?

If we consider the standard, both are integers of size 16 bits. On a typical 64-bit system, the size_t will be 64-bit, but unsigned int will be 32 bit. So we cannot use them interchangeably.

What is the size of Size_t in C?

size_t type is a base unsigned integer type of C/C++ language. It is the type of the result returned by sizeof operator. The type's size is chosen so that it can store the maximum size of a theoretically possible array of any type. On a 32-bit system size_t will take 32 bits, on a 64-bit one 64 bits.

When should I use Size_t?

Use size_t for variables that model size or index in an array. size_t conveys semantics: you immediately know it represents a size in bytes or an index, rather than just another integer. Also, using size_t to represent a size in bytes helps making the code portable.

Is Size_t signed or unsigned?

size_t is the unsigned integer type of the result of sizeof , _Alignof (since C11) and offsetof, depending on the data model. The bit width of size_t is not less than 16.


1 Answers

This is a known bug in gcc, fixed in versions 9.3.0 and above.

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 had already been reported:
Bug 87519 - -Wsign-conversion -Wconversion explicit cast fails to silence warning

The fix is commit 61e52125c935279af11b10d27060a96bff7477a4 in the gcc git repo, committed 2019-08-08.

like image 52
Keith Thompson Avatar answered Oct 18 '22 22:10

Keith Thompson