☰
  • 首页
  • 规则分类
  • 项目介绍
search
•••

避免类型转换造成数据丢失

12.1 ID_narrowCast
目录 › next › previous

应避免取值范围大的类型向取值范围小的类型隐式转换,相关显式转换也应在合理的条件下完成。

如果对象的值在新类型取值范围内,但无法用新类型精确表示,转换由实现定义;如果对象的值超出了新类型的取值范围,会导致数据丢失以及由实现定义或未定义的行为。

示例:

int i;
double d;
....
short s = i;  // Non-compliant, may cause data loss
long l = d;   // Non-compliant, may cause undefined behavior
float f = d;  // Non-compliant, may cause undefined behavior

将整数类型转为取值范围更小的整数类型会造成数据丢失,将浮点类型转为整数类型或取值范围更小的浮点类型,则可导致由实现定义或未定义的行为,所以应在转换前判断是否可以安全转换,或实现特定的转换逻辑。

下面给出判断转换是否安全的示例:

template <class To, class From>
struct Checker {
    static To cast(From x) {
        auto y = static_cast<To>(x);
        auto z = static_cast<From>(y);
        return x == z? y: throw DataLoss();
    }
};

template <class To, class From>
To checked_cast(From x) {
    return Checker<To, From>::cast(x);
}

函数 checked_cast 委托类 Checker 将源类型转为目标类型,再将目标类型转回源类型,如果经两次转换得到的值与转换前的值不符,说明转换存在数据丢失,抛出异常。

浮点型转换可能导致未定义的行为,所以应在转换之前判断取值范围,可通过特化 Checker 实现:

template <> struct Checker<long, double> {
    static bool check(double x) {
        return !isgreater(x, LONG_MAX) && !isless(x, LONG_MIN);
    }
    static long cast(double x) {
        return check(x)? static_cast<long>(x): throw DataLoss();
    }
};

template <> struct Checker<float, double> {
    static bool check(double x) {
        return !isgreater(fabs(x), FLT_MAX) && !isless(fabs(x), FLT_MIN);
    }
    static float cast(double x) {
        return check(x)? static_cast<float>(x): throw DataLoss();
    }
};

这样当 double 对象的值超出 long 或 float 对象的取值范围时会抛出异常。另外,浮点类型转整数类型时小数部分如何取舍、负数是否可以转为无符号数等问题均可以根据实际需求通过特化 Checker 来实现。

函数 checked_cast 的用法:

int i;
double d;
....
short s = checked_cast<short>(i);  // Compliant
long l = checked_cast<long>(d);    // Compliant
float f = checked_cast<float>(d);  // Compliant

依据

ISO/IEC 9899:1999 6.3.1.4(1)-undefined ISO/IEC 9899:1999 6.3.1.5(2)-undefined ISO/IEC 9899:2011 6.3.1.4(1)-undefined ISO/IEC 9899:2011 6.3.1.5(1)-undefined ISO/IEC 14882:2003 4.8(1)-undefined ISO/IEC 14882:2003 4.9(1)-undefined ISO/IEC 14882:2011 4.8(1)-undefined ISO/IEC 14882:2011 4.9(1 2)-undefined

参考

C++ Core Guidelines ES.46 MISRA C 2012 10.3 MISRA C 2012 10.5 MISRA C++ 2008 5-0-5 MISRA C++ 2008 5-0-6 SEI CERT FLP34-C
Copyright©2024 360 Security Technology Inc., Licensed under the Apache-2.0 license.