为什么这是一个不确定的行为? [英] Why is this an undefined behavior?

查看:184
本文介绍了为什么这是一个不确定的行为?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要回答的这个问题是这样的功能:

My answer to this question was this function:

inline bool divisible15(unsigned int x) 
{
    //286331153 = (2^32 - 1) / 15
    //4008636143 = (2^32) - 286331153
    return x * 4008636143 <= 286331153;
}

这工作完全在我的机器上用VS2008的编译器,但是这里它不会在所有的工作。

有没有人有一个想法,为什么我得到不同的编译器不同的结果? 无符号溢出不是不确定的行为。

Does anyone has an idea, why it I get different results on different compilers? unsigned overflow isn't undefined behavior.

重要提示:经过一些测试证实它比15取除法的余(但是不是所有的编译器)

Important note: after some test it was confirmed it is faster than taking the remainder of the division by 15. (However not on all compilers)

推荐答案

这不是未定义行为,它只是在C89和C99之间的C语言标准的重大更改。

It's not Undefined Behavior, it's just a breaking change in the C language standard between C89 and C99.

在C89,整数常量像4008636143,不适合在 INT 长整型,但适合做在 unsigned int类型是无符号,但在C99,他们要么长整型长长整型(取决于哪一个是可以容纳的值最小的一个)。其结果是,前pressions都得到使用64位,这导致了不正确的答案进行评价。

In C89, integer constants like 4008636143 that don't fit in an int or long int but do fit in an unsigned int are unsigned, but in C99, they are either long int or long long int (depending on whichever one is the smallest one that can hold the value). As a result, the expressions all get evaluated using 64 bits, which results in the incorrect answer.

Visual Studio是一个C89编译器,因此导致C89行为,但Ideone链接在编译C99模式。

Visual Studio is a C89 compiler and so results in the C89 behavior, but that Ideone link is compiling in C99 mode.

如果您使用的是用GCC编译,这变得更加明显 -Wall

This becomes more evident if you compile with GCC using -Wall:

test.c: In function ‘divisible15’:
test.c:8:3: warning: this decimal constant is unsigned only in ISO C90

从C89§3.1.3.2:

From C89 §3.1.3.2:

类型的整型常量是第一个相应的
  列表,在其中它的值可以被重新presented。无后缀十进制:INT,
  长整型,unsigned long int类型;后缀八进制或十六进制:INT,
  为unsigned int,long int类型,unsigned long int类型; [...]

The type of an integer constant is the first of the corresponding list in which its value can be represented. Unsuffixed decimal: int, long int, unsigned long int; unsuffixed octal or hexadecimal: int, unsigned int, long int, unsigned long int; [...]

C99§6.4.4.1/ 5-6:

C99 §6.4.4.1/5-6:

5)式的整型常量是第一个对应列表,其中它的值可以
  重新presented。

5) The type of an integer constant is the first of the corresponding list in which its value can be represented.

Suffix | Decimal Constant | Octal or Hexadecimal Constant
-------+------------------+------------------------------
none   | int              | int
       | long int         | unsigned int
       | long long int    | long int
       |                  | unsigned long int
       |                  | long long int
       |                  | unsigned long long int
-------+------------------+------------------------------
[...]


  
  

6)如果一个整常数不能重新由任何类型在其列表psented $ P $,它可以具有一个
  扩展整型,如果扩展整型可以重新present它的价值。如果所有的
  类型的列表中恒签署,扩展整数类型签章。 [...]

6) If an integer constant cannot be represented by any type in its list, it may have an extended integer type, if the extended integer type can represent its value. If all of the types in the list for the constant are signed, the extended integer type shall be signed. [...]

有关完整性,C ++ 03实际上确实有当整型常量太大,以适应在长整型未定义的行为。从C ++ 03§2.13.1/ 2:

For completeness, C++03 actually does have Undefined Behavior for when the integer constant is too big to fit in a long int. From C++03 §2.13.1/2:

该类型文本的整数依赖于它的形式,值和后缀。如果它是小数并且没有后缀,它具有
  首先这些类型中,它的价值可以重新presented的: INT 长整型;如果该值不能被重新presented
  作为长整型,其行为是不确定的。如果它是八进制或十六进制和没有后缀,它具有
  首先这些类型中,它的价值可以重新presented的: INT unsigned int类型长整型符号
  长整型
。 [...]

The type of an integer literal depends on its form, value, and suffix. If it is decimal and has no suffix, it has the first of these types in which its value can be represented: int, long int; if the value cannot be represented as a long int, the behavior is undefined. If it is octal or hexadecimal and has no suffix, it has the first of these types in which its value can be represented: int, unsigned int, long int, unsigned long int. [...]

在C ++ 11的行为等同于C99,看到C ++ 11§2.14.2/ 3。

The C++11 behavior is identical to C99, see C++11 §2.14.2/3.

要确保code一贯的行为时,作为编制或者C89,C99,C ++ 03和C ++ 11,简单的解决方法是让恒4008636143符号与<$ C $它后面添加C> U 为 4008636143u

To ensure that the code behaves consistently when compiled as either C89, C99, C++03, and C++11, the simple fix is to make the constant 4008636143 unsigned by suffixing it with u as 4008636143u.

这篇关于为什么这是一个不确定的行为?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆