此 C 代码试图找到负数的绝对值,但输出也是负数。谁能告诉我如何克服这个问题?
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <inttypes.h>
int main() {
int64_t a = 0x8000000000000000;
a = llabs(a);
printf("%" PRId64 "\n", a);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出
-9223372036854775808
Run Code Online (Sandbox Code Playgroud)
更新:
感谢您的所有回答。我知道这是一个非标准值,这就是我无法对其执行绝对操作的原因。但是,我确实在遗传编程模拟的实际代码库中遇到过这种情况。这里的“有机体”不了解 C 标准并坚持生成此值:) 谁能告诉我解决此问题的有效方法?再次感谢。
如果 的结果llabs()
无法在类型中表示long long
,则行为未定义。我们可以推断这就是这里发生的事情 - 超出范围的值 0x8000000000000000 在转换为 时被转换为值 -9223372036854775808 int64_t
,并且您的long long
值是 64 位宽,因此值 9223372035680087 不可用。
为了让您的程序具有定义的行为,您必须确保传递给的值llabs()
不小于-LLONG_MAX
. 您如何做到这一点取决于您 - 要么修改“有机体”,使其无法生成此值(例如,过滤掉那些创建立即不适合的超出范围值的值),要么在将其传递给之前限制该值llabs()
.
基本上,你不能。
的可表示值的范围int64_t
是-2 63到+2 63 -1。(并且标准要求int64_t
具有纯 2 的补码表示;如果不支持,则实现将不会定义int64_t
。)
该额外的负值没有相应的可表示的正值。
因此,除非您的系统具有大于 64 位的整数类型,否则您将无法将 的绝对值表示0x8000000000000000
为整数。
事实上,根据 ISO C 标准,您的程序的行为是未定义的。引用2011 ISO C 标准N1570 草案的第 7.22.6.1 节:
的ABS,实验室,和llabs函数计算的整数的绝对值Ĵ。如果结果无法表示,则行为未定义。
就此而言,结果
int64_t a = 0x8000000000000000;
Run Code Online (Sandbox Code Playgroud)
是实现定义的。假设long long
是 64 位,则该常量的类型为unsigned long long
。它隐式转换为int64_t
. 很可能,但不能保证,存储的值将是 -2 63或-9223372036854775808
. (甚至允许转换引发实现定义的信号,但这不太可能。)
(理论上,您的程序行为也可能只是实现定义的而不是未定义的。如果long long
宽度大于 64 位,则 的评估llabs(a)
不是未定义的,但结果的转换回int64_t
是实现定义的。在实践中,我从未见过long long
宽度超过 64 位的 C 编译器。)
如果您确实需要表示那么大的整数值,您可以考虑使用多精度算术包,例如GNU GMP。