最近,我公司的一位开发人员提交了一些代码,看起来像这样:
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();