C++隐式数字类型降级
C++ implicit numeric type demoting
最近,我注意到 C/C++ 似乎非常允许进行数值类型转换,因为它隐式地将双精度转换为 int。
测试:
环境: cpp.sh
, Standard C++ 14
, Compilation warnings all set
法典:
int intForcingFunc(double d) {
return d; // this is allowed
}
int main() {
double d = 3.1415;
double result = intForcingFunc(d);
printf("intForcingFunc result = %fn", result);
int localRes = d; // this is allowed
printf("Local result = %dn", localRes);
int staticCastRes = static_cast<int>(d); // also allowed
printf("Static cast result = %dn", staticCastRes);
}
编译期间没有警告问题。
文档不切地提到了主题,但忽略了问题的确切情况:
C++是一种强类型语言。许多转换(尤其是那些暗示对值的不同解释的转换(需要显式转换,C++称为类型转换。
我也尝试过使用托管语言 (C#(,但不允许所有这些情况(如预期的那样(:
static int intForcingFunc(double d)
{
// Not legal: Cannot implicitly convert type 'double' to 'int'
// return d;
return Convert.ToInt32(d);
}
static void Main(string[] args)
{
double d = 3.1415;
double result = intForcingFunc(d);
Console.WriteLine("intForcingFunc result = " + result);
// Not legal: Cannot implicitly convert type 'double' to 'int'
// int localRes = d;
int localRes = (int)d;
Console.WriteLine("local result = " + result);
Console.ReadLine();
}
为什么在强类型语言中允许此行为?在大多数情况下,这是不希望的行为。这背后的一个原因似乎是缺乏算术溢出检测。
不幸的是,这种行为是从 C 继承而来的,众所周知,C 在这些事情上"信任程序员"。
隐式浮点到整数转换的确切警告标志是 -Wfloat-conversion
,这也由 -Wconversion
启用。由于某种未知的原因,-Wall
、-Wextra
和 -pedantic
(cpp.sh 提供(不包括这些标志。
如果您使用 Clang,您可以-Weverything
它启用几乎所有警告。如果使用 GCC,则必须显式启用 -Wfloat-conversion
或 -Wconversion
,以便在执行此类转换时收到警告(以及您希望启用的其他有用标志(。
如果需要,您可以将其转换为错误,例如 -Werror-conversion
.
C++11 甚至引入了一种全新的更安全的初始化语法,称为统一初始化,您可以使用它来获取示例中隐式转换的警告,而无需启用任何编译器警告:
int intForcingFunc(double d) {
return {d}; // warning: narrowing conversion of 'd' from 'double' to 'int' inside { }
}
int main() {
double d{3.1415}; // allowed
int localRes{d}; // warning: narrowing conversion of 'd' from 'double' to 'int' inside { }
}
您没有指定正在使用的编译器,但实际上您可能没有启用所有警告。 它背后有一个故事,但净效应是g++ -Wall
实际上并没有启用所有警告(甚至没有关闭(。 其他的(例如 clang++(,为了与 g++ 直接替换兼容,必须做同样的事情。
这里有一篇关于为 g++ 设置强烈警告的好文章: https://stackoverflow.com/a/9862800/1541330
如果您使用的是 clang++,事情对您来说会容易得多:尝试使用 -Weverything
. 它完全符合您的期望(打开每个警告(。 您可以添加-Werror
编译器随后会将发生的任何警告视为编译时错误。 如果您现在看到要禁止显示的警告(错误(,只需将-Wno-<warning-name>
添加到命令中即可(例如。 -Wno-c++98-compat
(。
现在,每当发生隐式缩小转换(您未明确要求可能丢失数据的转换(时,编译器都会向您发出警告。 如果您希望进行缩小转换范围,则必须使用适当的转换,例如:
int intForcingFunc(double d) {
return static_cast<int>(d); //cast is now required
}
- ArduinoJson 6.15.2:JsonObject没有命名类型
- 防止主数据类型C++的隐式转换
- 大量序列中核苷酸类型的快速计数
- 如何从C++中的依赖类型中获得它所依赖的类型
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 是否可以初始化不可复制类型的成员变量(或基类)
- 如何获取std::result_of函数的返回类型
- 从父命名空间重载类型
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- Openssl 1.1.1d无效使用不完整的类型"struct dsa_st"
- 访问者访问变体并返回不同类型时出错
- 在VS2010-VS2015下编译时,如何使用decltype作为较大类型表达式的LHS
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- C++ 雷神库 - 使用资源加载器类时出现问题(不命名类型)
- 模板元程序查找相似的连续类型名称
- 是否可以从int转换为enum类类型
- 构造函数正在调用一个使用当前类类型的函数
- C++隐式数字类型降级
- 编译器警告 - 从函数返回时C++基本类型降级