简体   繁体   中英

Difference between unsigned and signed int pointer

Is there anything such as an unsigned int* which is different from int* . I know that unsigned has a higher range of values. Still, can't int* even point to any unsigned int ?

int * and unsigned int * are two different pointer types that are not compatible types. They are also pointers to incompatible types. For the definition of compatible types , please refer to § 6.2.7 in the C Standard (C11) .

Being pointers to incompatible types means that for example that this:

unsigned int a = 42;

int *p = &a;  // &a is of type unsigned int *

is not valid (the constraints of the assignment operator are violated).

Another difference between the two types is as for most other pointer types (although unlikely here) there is no guarantee from C they have the same size or the same representation.

Using an unsigned pointer to point to a signed version of the same type is defined by C Standard.

Therefore interpreting an int through an unsigned int pointer and vice-versa is valid.

ISO/IEC 9899:201x 6.5 Expressions, p7:

An object shall have its stored value accessed only by an lvalue expression that has one of the following types: 88)

— a type that is the signed or unsigned type corresponding to the effective type of the object,

— a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,

88) The intent of this list is to specify those circumstances in which an object may or may not be aliased.

Effective type is basically the type of the object:

The effective type of an object for an access to its stored value is the declared type of the object, if any.


An issue has been raised about the interpretation of the above rule. The following is my additional rationale about it.

This text below is listed purely for semantic reasoning of the word: corresponding ,and not for the direct rules it specifies.

6.2.5 Types

p6: For each of the signed integer types, there is a corresponding (but different) unsigned integer type (designated with the keyword unsigned) that uses the same amount of storage (including sign information) and has the same alignment requirements.

p9: The range of nonnegative values of a signed integer type is a subrange of the corresponding unsigned integer type, and the representation of the same value in each type is the same.41)

p12: For each floating type there is a corresponding real type, which is always a real floating type. For real floating types, it is the same type. For complex types, it is the type given by deleting the keyword _Complex from the type name.

p27: Further, there is the _Atomic qualifier. The presence of the _Atomic qualifier designates an atomic type. The size, representation, and alignment of an atomic type need not be the same as those of the corresponding unqualified type

6.2.6.2 Integer types

p2: For signed integer types, the bits of the object representation shall be divided into three groups: value bits, padding bits, and the sign bit. There need not be any padding bits; signed char shall not have any padding bits. There shall be exactly one sign bit. Each bit that is a value bit shall have the same value as the same bit in the object representation of the corresponding unsigned type

p5: The values of any padding bits are unspecified.54)A valid (non-trap) object representation of a signed integer type where the sign bit is zero is a valid object representation of the corresponding unsigned type, and shall represent the same value.

(And many more examples with identical usage of the word corresponding )

As you can see in the above snippets, Standard uses the word corresponding to refer to different types or types with different specifiers and/or qualifiers. Therefore, as seen in the above examples Standard uses the word as would be used in this example: qualified type is corresponding to type .

It would be illogical to suddenly use the word corresponding for a different purpose: referring to completely identically qualified/specified types and even confuse the matters more by including the words signed and unsigned in the same sentence for no good reason.

The intention of the 6.5, p7 is: a type that is the signed or unsigned type either a signed or unsigned type corresponding to the effective type of the object that othervise matches( corresponds ) to the target type. So for example: effective type is: int, int or unsigned int correspond to that type.

unsigned int * and int * are different types. To convert one to the other you must use a cast.

If you read a value through a pointer then it attempts to interpret the bits stored at that memory location as if they were bits for the type being pointed to by the pointer you are reading through.

If the bits at that memory location were not written by a pointer of the same type you are reading through, then this is called aliasing .

The strict aliasing rule specifies which types may or may not be aliased; alasing between a type's signed and unsigned versions is always permitted.

However, if the bits are not a valid representation of a value in the type you are reading , then it causes undefined behaviour.

On modern systems there are no such "trap" representations so you have no issue. But let's say you were on a 1's complement system that trapped on negative zero:

unsigned int x = 0xFFFFFFFF;
int *y = (int *)&x;
printf("%d\n", y);

The attempt to read y could cause a hardware fault or any other behaviour.

The value of the pointer is the same, but they are different types. A difference will arise depending on the way you interpret the pointer - for eg: dereferencing.

unsigned int *u;
int *d;
unsigned int v = 2147483648; /* 2^31 */
u = &v;
d = (int*) &v;
printf("%u\n", *u);
printf("%d\n", *d);

will output:

2147483648
-2147483648

The difference in the output arises because in printf("%d\\n", *d) , d is dereferenced and printed as if it points to a signed int , except it isn't. So you have to keep a distinction between the 2 types of pointers in your code.

It can point as both has the same size. The problem is this will introduce a hard to find bug, because you'll interpret a signed value as an unsigned or vice-versa.

A pointer is a number that is a memory address. So pointers have to have enough precision to be able to address all of memory for the implementation.

Whether you reference a signed or unsigned int makes no difference in the internal structure of the pointer, because, in theory anyway, the int or unsigned int could be almost anywhere in memory. The datatype (unsigned) has to be declared to "help" the compiler decide correctness of the code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM