C++ gcc size_t和sizeof算术转换为int

C++ gcc size_t和sizeof算术转换为int,c++,implicit-conversion,gcc-warning,C++,Implicit Conversion,Gcc Warning,我决定在启用了-Wsign转换的情况下测试编译一个项目,看看会出现什么警告,并遇到一些似乎不正确的情况,其中gcc的行为与clang不同。谁能告诉我哪个是正确的吗 我有一个函数,它采用size\u tparam: void func(size_t) {} 其他结构 struct Test {}; 和呼叫代码 int i = some_initialiser(); func(sizeof(Test) + static_cast<size_t>(i)); Clang在这里不发出警告

我决定在启用了-Wsign转换的情况下测试编译一个项目,看看会出现什么警告,并遇到一些似乎不正确的情况,其中gcc的行为与clang不同。谁能告诉我哪个是正确的吗

我有一个函数,它采用
size\u t
param:

void func(size_t) {}
其他结构

struct Test {};
和呼叫代码

int i = some_initialiser();
func(sizeof(Test) + static_cast<size_t>(i));

Clang在这里不发出警告,但如果我按预期删除函数调用中的
静态\u cast,则会发出警告。

警告是正确的

如果
i
的值为负值,则铸造将出现问题。您的函数应该返回一个无符号值(例如,unsigned int)

来自GCC文档-:

对于C++,还警告用户定义转换的混淆过载解决方案;以及从不使用类型转换运算符的转换:转换为
void
、相同类型、基类或对它们的引用。在C++中,默认情况下禁用关于符号和无符号整数之间的转换的警告,除非“代码> -WSCONNECT转换< /代码>被显式启用。


这是gcc中的一个已知错误,已在9.3.0及以上版本中修复

警告是有效的(编译器可以对任何他们喜欢的东西发出警告),但是gcc的行为与它自己的文档相矛盾。此问题有一个现有的bug报告(请参见下文)

下面是一个简单的测试用例,说明了这个问题:

#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);
}
在这种情况下,显式强制转换不会使警告静音

已报告此错误:


修复程序是2019-08-08提交的gcc git repo中的提交
61E522125C935279AF11B10D27060A96BFF747A4

gcc 9中更详细的错误消息指向作为警告源的静态_cast。如果只将静态_cast作为参数传递,警告就会消失。gcc似乎对将
int
转换为
size\u t
感到不满,但仅限于加法操作。显然,显式转换为
size\t
不足以关闭
+
操作符,但如果结果作为参数传递,它会保持沉默。值得注意的是,如果我将
sizeof
移动到局部变量中,如果声明为
auto
,它会发出警告,但如果声明为
size\u t
,则不会。可能是
sizeof
的返回类型有点奇怪?当然,警告涉及从
i
size\u t
的转换,而不是添加。也许clang将显式强制转换视为程序员元通信来抑制warning@M.M在提出这个问题时,我假设警告按照文档中的说明执行,并且只在隐式转换时发出警告,因此出于某种原因,我认为gcc在调用中的某个地方执行隐式转换。正如现在被接受的答案中所述,问题在于gcc实现的警告与其文档不匹配,而不是它正在进行意外的隐式转换。它不应该对显式转换发出警告,只对隐式转换发出警告。如果不使用
sizeof
@JohnIlacqua对强制转换的结果执行算术运算,则不会出现警告:谁说不应该对显式强制转换发出警告?编译器可以警告他们喜欢的任何东西。(顺便说一句,没有所谓的“隐式转换”;转换是一种显式转换。)@JohnIlacqua:但这种行为似乎与gcc的文档相矛盾。OP在调用gcc时显式使用了
-Wsign conversion
,文档中说“显式强制转换使警告静音”。我已更新了答案,并添加了gcc文档中的相关文本。希望现在能澄清这一点。@Tomer:您链接的文档为
-Wsign conversion
本身指定了(重点已添加):“警告可能会更改整数值符号的隐式转换,如将有符号整数表达式指定给无符号整数变量。显式强制转换会使警告静音。”,加法为
size\u t+size\u t
,结果作为
size\u t
传递,因此不会发生隐式转换。谢谢。我假设警告得到了正确的实现,并且发生了某种意外的隐式转换,但这是有意义的——出于某种原因,在某些上下文中,显式强制转换无法使警告静音。
#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);
}
$ 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);
      |                                ^~~~~~~~~~~~~~~~~~~~~~
$ 
'-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'.