为什么我可以用int初始化字符串



最近,我公司的一位开发人员提交了一些代码,看起来像这样:

char buf[50];
string str;
str = sprintf(buf, "%s", "test");
//proceeds to use str

问题是,它通过了CI,因为尽管设置了-Wall-Werror,编译器没有发出任何警告。

这不应该是一个明显的类型不匹配吗?没有std::to_string,就无法将整数分配给std::string类型。。。

我看了一下字符串赋值的列表,但我不知道在这种情况下触发了哪一个?它在用这些吗?

c-string (2) string& operator= (const char* s);
character (3) string& operator= (char c);

我猜是后者,但这似乎仍然是编译器失败,因为sprintf显然返回int而不是char

-Wall未涵盖的情况下,是否有我们本可以启用的警告可以拯救我们?

编辑:

我发现了一个相关的线程:https://stackoverflow.com/a/39285668/2516916

snprintf的返回值是一个int,它可以隐式转换为char,因此str = sprintf(buf, "%s", "test");调用character (3) string& operator= (char c);赋值运算符。

防止这种情况发生的通常方法是添加explicit关键字,但在您的情况下,由于std::string在库中,您实际上什么都做不了。

一种检测方法是使用UBSAN,它可以选择隐式强制转换。

希望能有所帮助!

我做了一些测试,下面是我的所有结果。编译此程序:

#include <iostream>    
#include <string>
using namespace std;
int main ()
{
string str;
str = 1000;
cout << str << "n";
return 0;
}

使用命令:

g++ -o test test.cpp

你会得到以下警告:

teste.cpp: In function ‘int main()’:
teste.cpp:10:11: warning: overflow in implicit constant conversion [-Woverflow]
str = 1000;

如果使用0到255之间的数字而不是1000,则不会收到警告。显然,如果数字在一个字符的范围内,编译器会尝试将该数字转换为一个字符,字符串类型会接受这一点。

但现在如果你这样做:

#include <iostream>    
#include <string>
using namespace std;
int number(){
return 100;
}
int main ()
{
int a = 100;
string str;
str = a;
cout << str << "n";
str = number();
cout << str << "n";
return 0;
}

你没有得到任何警告,作为输出你得到:

d
d

如果你在我的例子中用10000代替100,结果我只得到了两行空白。因此,经过分析,我相信发生的事情是,即使变量str试图接收的是int,编译器也试图通过将所有内容转换为你来让你的生活更轻松,但不幸的是,在这种情况下,它的结果恰恰相反。

在这里进行了一些研究之后,我终于找到了一个可以拯救你的组合:

g++ -o test test.cpp -Wconversion -Werror

使用-Wconversion可以将编译器进行的隐式转换转换为警告,使用-Werror可以将每个警告都转换为错误。

然后在上面的程序中,你会得到:

test.cpp: In function ‘int main()’:
test.cpp:13:11: error: conversion to ‘char’ from ‘int’ may alter its value [- 
Werror=conversion]
str = a;
^
test.cpp:17:17: error: conversion to ‘char’ from ‘int’ may alter its value [- 
Werror=conversion]
str = number();

最新更新