我试图了解隐式转换何时发生,并检测它们以提高代码库的质量。
我为此启用了Wconversion
和Wsign-conversion
。但是我遇到了编译器没有给出任何错误的情况。示例:
#include <iostream>
#include <array>
int main()
{
std::array<int, 10> vec{};
std::cout << vec[1] << std::endl;
}
编译:
$ g++ --std=c++14 -Wall -Wextra -Werror -pedantic -Wsign-conversion -Wconversion test.cpp
$
数组的大小和到operator[]
的索引都应为std::size_t
类型(无符号)。但是,我正在传递带符号的文字,似乎没有问题。我什至可以将1.0F
传递给operator[]
,编译器就可以了。
但是,如果我为operator[]
的索引创建一个带符号的变量,则编译器会发出有关隐式转换的警告。
幕后到底发生了什么?使用文字时是否发生隐式转换?为什么编译器没有给出错误?我正在Ubuntu 18.04上使用GCC 7.4。
答案 0 :(得分:8)
编译器不会警告您,因为它在编译时知道安全(即原始值和目标值相同)时会进行转换。当您这样做时:
vec[1.0F]
从编译器的角度来看,1.0F
和1
之间的值(精度损失)没有变化,因此编译器不会警告您。如果您尝试:
vec[1.2F]
...编译器会警告您,因为即使1.2F
会转换为1
,也会造成精度损失。
如果您使用的是编译时未知的值,例如:
float get_float();
vec[get_float()];
您将得到预期的警告,因为编译器事先不知道get_float()
的值,因此无法确定转换是否安全。
请注意,当期望使用常量表达式时(例如,std::array<int, 10>
),您将永远不会收到这样的警告,因为根据定义,常量表达式在编译时是已知的,因此编译器会知道之间是否存在问题给定值和转换后的值。
答案 1 :(得分:6)
存在警告“将有符号转换为无符号”,因为其中的一些可能会产生不良/意外的结果。将有符号的1
转换为无符号的1
不会出现任何问题。将-3
转换为无符号是有问题的。
使用变量,编译器无法(通常)知道运行时的值,因此必须警告潜在的转换问题。使用文字,它的值在编译时就已知,因此编译器可以默默地做正确的事情(当该值转换为OK时),或者在必要时发出警告/错误提示(当转换有问题时)。