abs(无符号长)有什么意义吗?
Does abs(unsigned long) make any sense?
我遇到了这段代码,顺便说一下,我的探查器将其报告为瓶颈:
#include <stdlib.h>
unsigned long a, b;
// Calculate values for a and b
unsigned long c;
c = abs(a - b);
这条线有什么比c = a - b;
更有趣的事情吗?这两个选项是否调用了未定义或实现定义的行为,是否有其他潜在的陷阱?请注意,包含 C <stdlib.h>
,而不是<cstdlib>
。
不,这没有意义。
如果您想要差异,请使用
c = (a > b) ? a - b : b - a;
或
c = max(a, b) - min(a, b);
无符号如果低于零将回绕(效果类似于添加 2大小(无符号长)* CHAR_BIT)
如果你正在寻找两个数字之间的差异,你可以写一个小模板,如下所示
namespace MyUtils {
template<typename T>
T diff(const T&a, const T&b) {
return (a > b) ? (a - b) : (b - a);
}
}
查看从C
继承的腹肌声明(因为您包括stdlib.h
)
int abs( int n );
long abs( long n );
long long abs( long long n ); // (since C++11)
//Defined in header <cinttypes>
std::intmax_t abs( std::intmax_t n ); // (since C++11)
和腹肌在C++
(从cmath
)
float abs( float arg );
double abs( double arg );
long double abs( long double arg );
如果您注意到,每个函数的参数和返回类型都signed
。因此,如果将无符号类型传递给这些函数之一,则会发生隐式转换unsigned T1 -> signed T2 -> unsigned T1
(其中T1
和T2
可能相同,并且在您的情况下long
T1
)。将无符号整数转换为有符号整数时,如果无法在有符号类型中表示,则行为取决于实现。
从 4.7 积分转换 [积分]
- 如果目标类型为无符号,则结果值最小 与源整数全等的无符号整数(模 2n,其中 n 为 用于表示无符号类型的位数)。[ 注:在 二的补码表示,这种转换是概念性的和 位模式没有变化(如果没有截断)。— 尾注]
如果- 目标类型是有符号的,则值保持不变(如果可以 以目标类型(和位域宽度)表示;否则 该值是实现定义的。
你是否认为它有意义,但是应用于无符号值abs()
当然可以返回传递的值以外的值。 这是因为abs()
接受int
参数并返回int
值。
例如:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
unsigned u1 = 0x98765432;
printf("u1 = 0x%.8X; abs(u1) = 0x%.8Xn", u1, abs(u1));
unsigned long u2 = 0x9876543201234567UL;
printf("u2 = 0x%.16lX; abs(u2) = 0x%.16lXn", u2, labs(u2));
return 0;
}
当编译为 C 或 C++ 时(在 Mac OS X 10.10.1 Yosemite 上使用 GCC 4.9.1),它会产生:
u1 = 0x98765432; abs(u1) = 0x6789ABCE
u2 = 0x9876543201234567; abs(u2) = 0x6789ABCDFEDCBA99
如果设置了无符号值的高位,则abs()
的结果不是传递给函数的值。
减法只是分散注意力;如果结果设置了最高有效位,则从abs()
返回的值将与传递给它的值不同。
当您使用 C++ 标头而不是问题中显示的 C 标头编译此代码时,它将无法编译并出现不明确的调用错误:
#include <cstdlib>
#include <iostream>
using namespace std;
int main(void)
{
unsigned u1 = 0x98765432;
cout << "u1 = 0x" << hex << u1 << "; abs(u1) = 0x" << hex << abs(u1) << "n";
unsigned long u2 = 0x9876543201234567UL;
cout << "u2 = 0x" << hex << u2 << "; abs(u2) = 0x" << hex << abs(u2) << "n";
return 0;
}
编译错误:
absuns2.cpp: In function ‘int main()’:
absuns2.cpp:8:72: error: call of overloaded ‘abs(unsigned int&)’ is ambiguous
cout << "u1 = 0x" << hex << u1 << "; abs(u1) = 0x" << hex << abs(u1) << "n";
^
absuns2.cpp:8:72: note: candidates are:
In file included from /usr/gcc/v4.9.1/include/c++/4.9.1/cstdlib:72:0,
from absuns2.cpp:1:
/usr/include/stdlib.h:129:6: note: int abs(int)
int abs(int) __pure2;
^
In file included from absuns2.cpp:1:0:
/usr/gcc/v4.9.1/include/c++/4.9.1/cstdlib:174:3: note: long long int std::abs(long long int)
abs(long long __x) { return __builtin_llabs (__x); }
^
/usr/gcc/v4.9.1/include/c++/4.9.1/cstdlib:166:3: note: long int std::abs(long int)
abs(long __i) { return __builtin_labs(__i); }
^
absuns2.cpp:10:72: error: call of overloaded ‘abs(long unsigned int&)’ is ambiguous
cout << "u2 = 0x" << hex << u2 << "; abs(u2) = 0x" << hex << abs(u2) << "n";
^
absuns2.cpp:10:72: note: candidates are:
In file included from /usr/gcc/v4.9.1/include/c++/4.9.1/cstdlib:72:0,
from absuns2.cpp:1:
/usr/include/stdlib.h:129:6: note: int abs(int)
int abs(int) __pure2;
^
In file included from absuns2.cpp:1:0:
/usr/gcc/v4.9.1/include/c++/4.9.1/cstdlib:174:3: note: long long int std::abs(long long int)
abs(long long __x) { return __builtin_llabs (__x); }
^
/usr/gcc/v4.9.1/include/c++/4.9.1/cstdlib:166:3: note: long int std::abs(long int)
abs(long __i) { return __builtin_labs(__i); }
^
因此,问题中的代码仅在仅使用 C 样式标头时编译;当使用 C++ 标头时不会编译。 如果添加<stdlib.h>
和<cstdlib>
,则存在额外的重载,可以使调用更加模糊。
abs()
的调用中添加(不)适当的强制转换,你可以使代码编译,并且有符号数量的绝对值可以与原始有符号数量不同,这并不奇怪:
#include <cstdlib>
#include <iostream>
using namespace std;
int main(void)
{
unsigned u1 = 0x98765432;
cout << "u1 = 0x" << hex << u1 << "; abs(u1) = 0x" << hex << abs(static_cast<int>(u1)) << "n";
unsigned long u2 = 0x9876543201234567UL;
cout << "u2 = 0x" << hex << u2 << "; abs(u2) = 0x" << hex << abs(static_cast<long>(u2)) << "n";
return 0;
}
输出:
u1 = 0x98765432; abs(u1) = 0x6789abce
u2 = 0x9876543201234567; abs(u2) = 0x6789abcdfedcba99
道德:不要使用C++代码中C++等效项的 C 标头;请改用 C++ 标头。
当 c=a-b 为负数时,如果 c 是无符号数,c 不是准确的答案。使用 abs 来保证 c 是一个正数。
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 是什么导致了这种使用三进制而不是短整型的有符号int到无符号int转换
- C++ C4244 =':从"std::streamsize"转换为"无符号短",可能会丢失数据;有什么解决办法吗?
- 无符号长整型和无符号 int 之间有什么区别,这 2 种类型应该如何在 c# 中封送?
- 在C++中,将无符号整数转换为八进制表示,反之亦然的最佳方法是什么
- 计算机使用什么方法添加无符号整数
- “*(无符号整数*)((无符号整数)块 + n*i)”是什么意思
- 通过无符号 char 别名进行对象访问,加载和存储时会发生什么?
- 对于不确定值的无符号字符类型,标准中特殊语言对于左值到右值的转换有什么意义?
- 对于具有 3 个无符号字符和一个 int 的结构来说,对于unordered_map来说,什么是好的哈希函数?
- 无符号整数的负数会发生什么
- 获取无符号字符 * 的 strlen 的正确方法是什么
- ostream 和basic_ostream<无符号字符>有什么区别?
- abs(无符号长)有什么意义吗?
- SNMP 类型无符号32 的正确编码是什么
- 按位左移一个带有 16 的无符号字符是什么意思
- 无符号短 int 和无符号 int 或无符号短有什么区别
- 有符号/无符号比较警告是什么意思
- 将无符号字符数组转换为IP字符串的最快方法是什么
- 将有符号整数值转换为可排序的无符号C++的标准兼容方法是什么?