C整数隐式转换

C integer implicit conversion

我正在尝试了解以下转换的机制

#include <stdio.h>
#include <stdint.h>

int main() {
    
    int a = 0xffffffff;  
    printf("%d", a); // prints -1
    return 0;
}

根据 integer constant0xffffffff 的类型是 unsigned int。这可以通过 printf("%s", 0xffffffff);

轻松检查

现在,根据implicit conversion semantics

"Integer promotion is the implicit conversion of a value of any integer type with rank less or equal to rank of int [...] to the value of type int or unsigned int."

并且,如下所述

"the ranks of all signed integer types equal the ranks of the corresponding unsigned integer types"

所以晋升适用,因为 unsigned int 的排名与 int 的排名相同。

该促销定义为

"If int can represent the entire range of values of the original type (or the range of values of the original bit field), the value is converted to type int. Otherwise the value is converted to unsigned int"

但是,我不明白的是,int不能表示unsigned int 4,294,967,295,但它仍然被转换为int。而且这种情况发生 没有任何缩小警告。为什么会这样?

由于常量 0xffffffff(假设 int 是 32 位)具有类型 unsigned int,用于初始化类型 int 的对象,这涉及从 unsigned intint.

的转换

整数类型之间的转换在C标准的6.3.1.3节中有描述:

1 When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.

2 Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.

3 Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised

第 3 段适用于这种情况。有问题的值超出了目标类型的范围,并且目标已签名。因此发生了实现定义的转换。

如果你使用-Wconversion标志用gcc编译,它会给你一个警告:

x1.c:6:5: warning: conversion of unsigned constant value to negative integer [-Wsign-conversion]
     int a = 0xffffffff;  

还有:

This can be easily checked by doing printf("%s", 0xffffffff);

这会调用 undefined behavior,因为 %s 格式说明符需要 char *,它指向一个以 null 结尾的字符串。您传递的值不是这种类型,可能不是有效的内存地址。

整数提升在这里也不适用,因为没有比 intunsigned int.

等级更低的表达式

问题是你正在将一个无符号数(值 0xffffffff)转换(好吧,不是你,而是代表你的编译器)到一个 signed int,它在它的范围之外值的有效范围(您试图将 4294967296 转换为 int,但 int 仅涵盖 -2147483648 ... +2147483647),因此您会得到未定义的行为。

根据您使用的编译器(和体系结构),您可以获得不同的值,甚至会因为溢出而出现异常。我的猜测是您的编译器使用二进制补码,它只是将数字重新解释为其等效的二进制表示形式,即 -1-1 在内部表示为四个字节 0xff另一个)。