20 April 2023

C++ 核心指南目录

“Avoid lossy (narrowing, truncating) arithmetic conversions”

坏例子

变窄类型转换操作

double d = 7.9;
int i = d;    // bad: narrowing: i becomes 7
cout << d << ", " << i << endl;
i = (int) d;  // bad: we're going to claim this is still not explicit enough
cout << d << ", " << i << endl;
7.9, 7
7.9, 7
void f(int x, long y, double d)
{
    char c1 = x;   // bad: narrowing
    char c2 = y;   // bad: narrowing
    char c3 = d;   // bad: narrowing
    cout << c1 << ", " << c2 << ", " << c3;
}

int main()
{
    f(10099, 1000000099, 9999990.999999);
    return EXIT_SUCCESS;
}
s, c, v

注意

指南支持库 GSL 提供narrow_cast操作和 narrow 操作。如果允许数值丢失,那么可以用narrow_cast;如果认为数值丢失是一种错误,那么用 narrow 操作,如果类型转换的过程中数值丢失,它会抛出narrow_error

double d = 7.9;
double d2 = 8.0;
int i{};
i = gsl::narrow_cast<int>(d);   // OK (you asked for it): narrowing: i becomes 7
cout << "gsl::narrow_cast<int>(" << d << ") = " <<  i << endl;
try {
    i = gsl::narrow<int>(d2);
    cout << "gsl::narrow<int>(" << fixed << setprecision(1)
         << d2 << ") = " << i << endl;
    i = gsl::narrow<int>(d);        // OK: throws narrowing_error
} catch (gsl::narrowing_error& e) {
    cout << e.what();
}
gsl::narrow_cast<int>(7.9) = 7
gsl::narrow<int>(8.0) = 8
std::exception

负数浮点类型也可以用 gsl 类型转换操作:

double d = -7.9;
unsigned u = 0;

u = d;                               // bad: narrowing
cout << u << endl;

u = gsl::narrow_cast<unsigned>(d);   // OK (you asked for it): u
                                     // becomes 4294967289
cout << "gsl::narrow_cast<int>(" << d << ") = " <<  u << endl;

try {
    u = gsl::narrow<unsigned>(d);    // OK: throws narrowing_error
} catch (gsl::narrowing_error& e) {
    cout << e.what();
}
4294967289
gsl::narrow_cast<int>(-7.9) = 4294967289
std::exception

注意

此规则不适用于转换到布尔型的某些特殊操作:

if (ptr) do_something(*ptr);   // OK: ptr is used as a condition
bool b = ptr;                  // bad: narrowing

强化

好的分析工具能检测到所有窄转换操作。然而,把所有窄转换都打上标记,可能会导致太多误报。

建议

标记所有从浮点型到整型的类型转换。也包括浮点到 char,双精度型到 int。

标记所有 longchar 的类型转换。

函数参数出现窄类型转换也很值得怀疑!