这对int64_t的处理是GCC和Clang的错误吗?

前端之家收集整理的这篇文章主要介绍了这对int64_t的处理是GCC和Clang的错误吗?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

现在,你们中的一些人会想要大喊未定义的行为,但是有一个问题. int64_t类型不是由C标准定义,而是由POSIX定义.POSIX将此类型定义为:

a signed integer type with width N,no padding bits,and a two’s-complement representation.

它不会留下这个实现来定义,并且绝对不允许将它视为无界整数.

linux$cat x.c
#include dio.h>
#include 

显然,这里有一个问题……它是什么?
我错过了某种隐性演员吗?

最佳答案
你不需要去POSIX对它进行排序,ISO C控制这个特定的方面(下面的参考是C11标准).

这个答案的其余部分将成为所有“语言律师”,以显示为什么将未添加的行为添加到已签名的值中,以及为什么两个答案(真和假)都有效.

首先,您在ISO中未定义int64_t的争论并不十分正确.第7.20.1.1节精确宽度整数类型在引用intN_t类型时指出:

The typedef name intN_t designates a signed integer type with width N,and a two’s complement representation. Thus,int8_t denotes such a signed integer type with a width of exactly 8 bits.

These types are optional. However,if an implementation provides integer types with widths of 8,16,32,or 64 bits,and (for the signed types) that have a two’s complement representation,it shall define the corresponding typedef names.

这就是为什么你不需要担心POSIX以某种方式定义这些类型的原因,因为ISO定义它们完全相同(两个补码,没有填充等),假设它具有适当的能力.

所以,既然我们已经建立了ISO确定它们(如果它们在实现中可用),现在让我们看看6.5 Expressions / 5:

If an exceptional condition occurs during the evaluation of an expression (that is,if the result is not mathematically defined or not in the range of representable values for its type),the behavior is undefined.

添加两个相同的整数类型肯定会给你相同的类型(至少在int64_t的等级,远高于整数提升完成的点1),因为这是由6.3.1.8中规定的通常的算术转换决定的.在处理各种浮点类型(其中int64_t不是)的部分之后,我们看到:

If both operands have the same type,then no further conversion is needed.

在同一部分的早期,您会找到一个声明,该声明在找到常见类型后指示结果的类型:

Unless explicitly stated otherwise,the common real type is also the corresponding real type of the result.

因此,假设INT64_MAX 1的结果实际上不适合int64_t变量,则行为未定义.

根据你的注释,int64_t的编码表明添加一个将包装,你必须明白,它不会改变它根本未定义的子句.在这种情况下,实现仍然可以自由地执行任何操作,即使根据您的想法没有意义.

并且,在任何情况下,表达式INT64_MAX 1> INT64_MAX(其中1经历整数提升为int64_t)可以简单地编译为1,因为可以说比实际递增值和进行比较更快.这是正确的结果,因为任何东西都是正确的结果:-)

从这个意义上讲,它与实现转换没有什么不同:

int ub (int i) { return i++ * i++; } // big no-no
:
int x = ub (3);

进入更简单,几乎肯定更快:

int x = 0;

您可能认为答案会更好,因为9或12(取决于何时执行副作用)但是,如果未定义的行为是打破编码器和编译器之间的契约,编译器可以自由地做任何想做的事情.

在任何情况下,如果你想要一个定义良好的函数版本,你可以选择以下内容

int stupid (int64_t a) {
    return (a == INT64_MAX) ? 0 : 1;
}

这可以在不诉诸未定义的行为的情况下获得所需/预期的结果:-)

1如果int的宽度实际上大于64位,则此处可能存在边缘情况.在这种情况下,很可能整数提升将强制int64_t为int,允许表达式被很好地定义.我没有详细研究过,所以可能是错的(换句话说,不要把它视为我答案的福音部分)但是值得记住的是检查你是否得到了一个int的实现超过64位宽.

猜你在找的Linux相关文章