简体   繁体   English

使用带有 uint64_t 类型的内置溢出函数

[英]Using builtin overflow functions with uint64_t types

I am currently writing a program which makes heavy use of the uint64_t type, to enhance compatibility across platforms.我目前正在编写一个大量使用uint64_t类型的程序,以增强跨平台的兼容性。 As it happens, there are a lot of possibilities for overflows in my program, so I want to use the built in overflow functions from gcc .碰巧的是,我的程序中有很多溢出的可能性,所以我想使用gcc内置溢出函数

Unfortunately, they are only defined on int s, long int s, long long int s and so on.不幸的是,它们只在int s、 long int s、 long long int s 等上定义。 The uintX_t types guarantee to always be of size X bits, which is not the case for those types eg a long int is not guaranteed to be 64 bit. uintX_t类型保证总是大小为 X 位,这些类型不是这种情况,例如long int不能保证为 64 位。 This makes me think, that the builtin overflow functions can't be used here.这让我觉得,内置的溢出函数不能在这里使用。

How to solve this issue now?现在如何解决这个问题?

I have two approaches:我有两种方法:

  1. using the UINT64_MAX constant from stdint.h and make the overflow prediction myself.使用stdint.hUINT64_MAX常量并自己进行溢出预测。 However, I am not a friend of "re-inventing the wheel".但是,我不是“重新发明轮子”的朋友。

  2. using the eg __builtin_add_overflow_p function to only check for the overflow.使用例如__builtin_add_overflow_p函数仅检查溢出。 However, I am not 100% sure if they can be applied to uint64_t .但是,我不是 100% 确定它们是否可以应用于uint64_t

What is the best way?什么是最好的方法? Am I overseeing something obvious?我在监督一些明显的事情吗?

Using builtin overflow functions with uint64_t使用带有uint64_t内置溢出函数
... to use the built in overflow functions from gcc . ...使用来自 gcc内置溢出函数

To form your own builtin_uadd64_overflow() , without "re-inventing the wheel", use _Generic to steer function selection.要形成您自己的builtin_uadd64_overflow() ,而不是“重新发明轮子”,请使用_Generic来引导函数选择。

#define builtin_uadd64_overflow(a,b,r) _Generic(*(r), \
  unsigned: __builtin_uadd_overflow, \
  unsigned long: __builtin_uaddl_overflow, \
  unsigned long long: __builtin_uaddll_overflow \
  )(a,b,r)

Unsigned overflow is defined behaviour according to the C standard (§6.2.5/9)无符号溢出是根据 C 标准(第 6.2.5/9 节)定义的行为

A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.涉及无符号操作数的计算永远不会溢出,因为无法由结果无符号整数类型表示的结果以比结果类型可以表示的最大值大 1 的数为模减少。

So when you have an addition like;所以当你有一个额外的东西时;

uint64_t a, b, c;

c = a + b;

you can check, if the operation overflowed by testing您可以通过测试检查操作是否溢出

int overflowed = c < a || c < b;

Of course, you can wrap this into a function if you need.当然,如果需要,您可以将其包装到函数中。

The following functions should work pretty well for objects of type int or long long ;对于intlong long类型的对象,以下函数应该可以很好地工作; on 32-bit platforms, the int functions will be much more efficient than approaches using long long ;在 32 位平台上, int函数将比使用long long方法高效得多; on 64-bit platforms, the long long functions will be as efficient as the int ones.在 64 位平台上, long long函数将与int函数一样高效。

int safe_add1(int  *value, int  delta) {
    int val = *value;
    int sum = delta+(unsigned int)val;
    if (((sum ^ val) & (sum ^ delta)) < 0)
        return -1;
    *value = sum;
    return 0;
}
int safe_add2(long long  *value, long long  delta) {
    long long val = *value;
    long long sum = delta+(unsigned long long)val;
    if (((sum ^ val) & (sum ^ delta)) < 0)
        return -1;
    *value = sum;
    return 0;
}

Note that to guarding against overflow really efficiently would in many cases require a compiler to use integer overflow as an invitation to implement a conforming extension that would define integer overflow semantics in a way that was tight enough to meet program requirements, but loose enough to allow optimizations.请注意,为了真正有效地防止溢出,在许多情况下需要编译器使用整数溢出作为实现符合扩展的邀请,该扩展将以一种足够紧以满足程序要求的方式定义整数溢出语义,但足够松散以允许优化。 For example, if a program wants to compute x+y > z while ensuring that no overflows that would yield numerically-wrong behavior go undetected, and if a compiler knows that x and z will be equal, the optimal way to meet requirements would be to compute y > 0 , since that behavior would be numerically correct whether or not x+y could be computed without overflow.例如,如果程序想要计算x+y > z同时确保不会检测到会产生数值错误行为的溢出,并且如果编译器知道xz相等,那么满足要求的最佳方法是计算y > 0 ,因为无论x+y是否可以在没有溢出的情况下计算,该行为在数值上都是正确的

Unfortunately, unless compilers provide extensions to recognize such constructs, there will be no way to write particularly efficient overflow-checking code.不幸的是,除非编译器提供扩展来识别此类结构,否则将无法编写特别有效的溢出检查代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM