为什么在C/C++中不能用常量替换变量?

ee7vknir  于 7个月前  发布在  C/C++
关注(0)|答案(2)|浏览(114)

这里有一个非常简单的C/C++代码,让我感到惊讶,因为它没有给予相同的结果。

float f = -123.123f;
unsigned u1 = -123.123f;
unsigned u2 = f;
printf("%d %d\n", u1, u2); // 0 -123
printf("%u %u\n", u1, u2); // 0 4294967173

字符串
输出给出:

0 -123
0 4294967173


为什么结果会不一样?
这是令人担忧的,因为具有相同含义的符号在语言中不能被替换。
我在programiz.com网站上用C++编译器测试了这个例子。
我以为结果是一样的。
谢谢你的回答,让我们忘记打印部分。理解,它是未定义的,所以值可能会有所不同。

bcs8qyzn

bcs8qyzn1#

C标准没有定义将小于或等于−1的浮点数转换为无符号整数类型的行为。C 2018 6.3.1.4 1说:
当一个真实的浮点类型的有限值被转换为除_Bool之外的整数类型时,小数部分被丢弃(即,该值被向零截断)。如果整数部分的值不能用整数类型表示,则行为未定义。
因此,对于-123.123f,小数部分将被丢弃,留下-123。然后整数部分-123不能用无符号类型表示,因此没有定义行为。
在使用无符号类型的大多数操作中,数学结果以2w 为模进行 Package ,其中 w 是无符号类型的宽度(以位为单位)。例如,unsigned u = 0u - 123u;unsigned u = -123;都将 Package 数字并产生定义的结果(对于16位unsigned int,为65,536 − 123 = 65,413;对于32位unsigned int,为4,294,967,296 − 123 = 4,294,967,173)。对于浮点转换,C标准并没有说这种 Package 会发生。2这种行为没有定义。
在您的特定情况下可能发生的情况是,在编译时,编译器使用自己的代码来生成将浮点数转换为unsigned的结果,并且此代码生成零,而对于从变量的转换,编译器生成一个处理器指令来执行转换,并且该处理器指令生成对应于-123的位(二进制补码)或4,294,967,173然后,当这些位被发送到printf以与%d一起打印时,它将这些位的解释打印为int,输出为“-123”。(这是进一步未定义的行为,因为%d不应该与unsigned int一起使用,并且C标准没有定义这种不匹配会发生什么。通常将unsigned int的位解释为int

luaexgnf

luaexgnf2#

  • 第一个月

这有未定义的行为,因为您使用的是%d而不是%u

  1. unsigned u1 = -123.123f;
    这有未定义的行为,因为-123.123的截断部分不能在unsigned中表示。来自C23草案:
    6.3.1.4真实的浮点数和整数
    1.当一个标准浮点类型的有限值被转换为一个非bool的整数类型时,小数部分会被丢弃(也就是说,该值会被向零截断)。如果整数部分的值不能用整数类型表示,则该行为是未定义的。
    65)将整数类型的值转换为无符号类型时执行的转换操作在将真实的浮点类型的值转换为无符号类型时不需要执行。因此,可移植的真实的浮点值的范围为(−1, Utype_MAX + 1)
  2. unsigned u2 = f;
    这与上面提到的问题相同。
    一个可能的转换 * 与 * 定义的行为:
#include <limits.h>
#include <stdio.h>

int main(void) {
    float f = -123.123f;
    unsigned u1 = (int)-123.123f;   // the int value will be -123
    unsigned u2 = (int)f;           // again, the int value will be -123
    printf("%u %u\n", u1, u2);      // prints two large values

    printf("%u\n", UINT_MAX - 122); // prints the same large value
}

字符串
打印的大值是因为unsigned变量将在零处“回绕”:
0u - 1 == UINT_MAX0u - 123UINT_MAX - 122相同。

相关问题