是否存在与int*
不同的unsigned int*
?我知道unsigned
类型具有更高的值范围。但是,int*
难道不能指向任何unsigned int
吗?
是否存在与int*
不同的unsigned int*
?我知道unsigned
类型具有更高的值范围。但是,int*
难道不能指向任何unsigned int
吗?
int *
和unsigned int *
是两种不兼容的指针类型,它们也分别是指向不兼容类型的指针。关于"兼容类型"的定义,请参考C标准(C11)中的§ 6.2.7。
指向不兼容类型的指针意味着例如这样的情况:
unsigned int a = 42;
int *p = &a; // &a is of type unsigned int *
无效(违反赋值运算符的限制约束)。
这两种类型之间的另一个差异是,与大多数其他指针类型一样(尽管在这里不太可能),C语言不能保证它们具有相同的大小或相同的表示形式。
int *p = (int *)&a
是有效的。您的回答只解决了编译时是否需要强制转换的问题,然而我认为OP询问的是如果包括强制转换,运行时会发生什么。 - M.M使用无符号指针指向有符号类型的相同类型是由C标准定义的。
因此,通过无符号int指针解释int类型数据以及通过有符号int指针解释unsigned int类型数据都是有效的。
ISO/IEC 9899:201x 6.5 表达式, p7:
一个对象的存储值只能通过具有以下类型之一的lvalue表达式访问: 88)
— 对象的有效类型对应的已签名或未签名类型
— 对象的有效类型的已修饰版本对应的已签名或未签名类型
88) 此列表的目的是指定对象可能或不可能别名的情况。
有效类型基本上是对象的类型:
对于访问其存储值的对象,其有效类型是对象的已声明类型(如果存在)。
关于上述规则的解释存在争议。以下是我对此的额外解释。
下面的文本仅用于解释“corresponding”一词的语义,而不是直接规定的规则。
6.2.5 类型
p6:对于每个有符号整数类型,都有一个相应的(但不同)无符号整数类型(用关键字unsigned指定),它使用相同的存储空间(包括符号信息)并具有相同的对齐要求。
p9:有符号整数类型的非负值范围是相应的无符号整数类型的子范围,并且在每种类型中表示相同的值。41)
p12:对于每种浮点类型,都有一个相应的实数类型,它始终是实浮点类型的一种。
对于实数浮点类型,它是相同的类型。对于复杂类型,它是通过从类型名称中删除关键字“_Complex”得到的类型。
p27: 此外,还有_Atomic限定符。_Atomic限定符的存在指定了原子类型。原子类型的大小、表示和对齐方式不一定与相应的非限定类型相同。
6.2.6.2 整数类型
p2: 对于有符号整数类型,对象表示的位应分为三组:值位、填充位和符号位。不需要有任何填充位;signed char不得有任何填充位。应该恰好有一个符号位。每个值位上的位应与相应无符号类型的对象表示中的相同位具有相同的值。
p5: 任何填充位的值都是未指定的。54)当符号位为零的有符号整数类型的有效(非陷阱)对象表示是相应无符号类型的有效对象表示,并且应表示相同的值。
(还有很多使用单词corresponding的相同例子)
如您在上面的片段中所看到的,标准使用单词“ corresponding”来引用具有不同类型或具有不同修饰符/限定符的类型。因此,正如上面的例子中所见,标准使用单词,就像在此示例中使用的单词一样:限定类型对应于类型。
突然将单词“ corresponding”用于不同的目的,即引用完全相同的限定/规定类型,甚至无谓地将有符号和无符号的单词放在同一句话中,是不合逻辑的。
6.5、p7 的意图是:一种有符号或无符号类型
,要么是与对象的有效类型相对应的有符号或无符号类型,要么与目标类型匹配(相对应)。例如:有效类型是 int,则 int 或 unsigned int 对应于该类型。
int *
和 unsigned int *
可以互换使用而不需要强制转换吗? - Gamal Othmanunsigned int *
和int *
是不同的类型。 要将其中一个转换为另一个,必须使用强制转换。
如果您通过指针读取值,则尝试将存储在该内存位置上的位解释为指针正在读取的类型所指向的类型的位。
如果该内存位置上的位不是由与您正在读取的指针相同类型的指针编写的,则称此为别名。
严格别名规则指定哪些类型可能或不可能具有别名; 类型的signed
和unsigned
版本之间始终允许别名。
但是,如果这些位不是类型中值的有效表示,则会导致未定义的行为。
在现代系统中,没有这样的“陷阱”表示,因此您不会遇到问题。 但假设您在一个负零陷阱的1的补码系统上:
unsigned int x = 0xFFFFFFFF;
int *y = (int *)&x;
printf("%d\n", y);
试图读取y
可能会导致硬件故障或任何其他行为。
char *
和unsigned char *
交替使用,这样做虽然方便处理二进制和文本混合缓存的数据,但也让人感到有些烦恼。 - M.Munsigned int *u;
int *d;
unsigned int v = 2147483648; /* 2^31 */
u = &v;
d = (int*) &v;
printf("%u\n", *u);
printf("%d\n", *d);
将输出:
2147483648
-2147483648
输出结果的差异是因为在 printf("%d\n", *d)
中,d
被解引用并打印,就好像它指向一个 signed int
一样,但实际上并不是。因此,您需要在代码中区分这两种指针。
u = d = &v;
。这违反了赋值运算符的限制条件。你需要进行显式转换(即强制类型转换)。 - ouah它可以指向两个相同大小的值。问题在于,这将引入难以发现的错误,因为您将会将有符号的值解释为无符号的值或反之亦然。
指针是一个内存地址的数字。因此,指针必须具有足够的精度,以便能够寻址所有实现的内存。
无论您引用有符号还是无符号整数,在指针的内部结构上都没有区别,因为理论上,int或unsigned int几乎可以在内存中的任何位置。数据类型(unsigned)必须声明为“帮助”编译器决定代码的正确性。