05-08-2020, 07:59 PM
因为无符号数是非负的,那么对它取绝对值显然是它本身。所以C/C++中的绝对值函数的参数类型是有符号的。但是,如果不小心传入了无符号整数,会发生什么呢?
首先看C语言。abs函数在stdlib.h里面,函数原型是 int abs(int). 那么无论怎么用 abs 函数,C 语言都是先把参数转为 int,再调用 abs. 事实上,对 uint8_t, uint16_t, uint32_t 求 abs,编译器都不会有警告。如果没包含 stdlib.h 头文件,GCC 会使用内建的 abs 函数,此时会有一个 uint32_t 和 int 不匹配的警告(-Wbuiltin-declaration-mismatch)。
C++ 因为有函数重载,会复杂一些。实际上就是把浮点和 long, long long 类型的绝对值函数重载了。
首先把头文件从 stdlib.h 改成 cstdlib,结果没发现 C++ 编译器报错。但是如果有 using namespace std 的话,那么 C++ 编译器会报错,针对的是 abs(uint32_t&),认为它有歧义。C++ 的 abs 有下列这些函数原型:
- abs(int): C 标准库的 stdlib.h 里的 abs
- std::abs(__float128)
- std::abs(__int128)
- std::abs(long double)
- std::abs(float)
- std::abs(double)
- std::abs(long long int)
- std::abs(long int)
就是说 std::abs 把 int 类型之外的所有有符号类型都覆盖了。而 uint32_t 作为 abs 的参数时,编译器不知道应该把它转成什么类型,于是就报了错误。
但是 uint8_t 和 uint16_t 并没有这个问题,事实上对它们用 abs 的时候,都会把它们转成 int 类型,而无符号数转成更长的整数的时候,用的是0扩展,于是对它们求绝对值就是它们本身。
首先看C语言。abs函数在stdlib.h里面,函数原型是 int abs(int). 那么无论怎么用 abs 函数,C 语言都是先把参数转为 int,再调用 abs. 事实上,对 uint8_t, uint16_t, uint32_t 求 abs,编译器都不会有警告。如果没包含 stdlib.h 头文件,GCC 会使用内建的 abs 函数,此时会有一个 uint32_t 和 int 不匹配的警告(-Wbuiltin-declaration-mismatch)。
C++ 因为有函数重载,会复杂一些。实际上就是把浮点和 long, long long 类型的绝对值函数重载了。
首先把头文件从 stdlib.h 改成 cstdlib,结果没发现 C++ 编译器报错。但是如果有 using namespace std 的话,那么 C++ 编译器会报错,针对的是 abs(uint32_t&),认为它有歧义。C++ 的 abs 有下列这些函数原型:
- abs(int): C 标准库的 stdlib.h 里的 abs
- std::abs(__float128)
- std::abs(__int128)
- std::abs(long double)
- std::abs(float)
- std::abs(double)
- std::abs(long long int)
- std::abs(long int)
就是说 std::abs 把 int 类型之外的所有有符号类型都覆盖了。而 uint32_t 作为 abs 的参数时,编译器不知道应该把它转成什么类型,于是就报了错误。
但是 uint8_t 和 uint16_t 并没有这个问题,事实上对它们用 abs 的时候,都会把它们转成 int 类型,而无符号数转成更长的整数的时候,用的是0扩展,于是对它们求绝对值就是它们本身。