Compare pointers in C. Are they signed or unsigned?

Hey. I am sure that this should be a general question, but I cannot find the answer when I look for it. My question mainly concerns two pointers. I want to compare their addresses and determine if one of them is larger. I would expect that during the comparison all addresses will be unsigned. Is this true and is it different from C89, C99 and C ++? When I compile with gcc, the comparison is unsigned.

If I have two pointers that I compare as follows:

char *a = (char *) 0x80000000; //-2147483648 or 2147483648 ? char *b = (char *) 0x1; 

Then a greater. Is this guaranteed by the standard?


Edit to update what I'm trying to do. I have a situation where I would like to determine that if there is an arithmetic error, it will not force the pointer to go beyond. Right now I have the starting address of the array and the ending address. And if there is an error, and the pointer calculation is incorrect, and outside of the valid memory addresses for the array, I would like to make sure that access violation does not occur. I believe I can prevent this by comparing a suspicious pointer that was returned by another function and determining if it is in a valid array range. The question of negative and positive addresses is related to whether I can make comparisons, as discussed above in my original question.

I appreciate the answers so far. Based on my editing, will you say that what I'm doing is undefined behavior in gcc and msvc? This is a program that will only work on Microsoft Windows.

Here is a more simplified example:

 char letters[26]; char *do_not_read = &letters[26]; char *suspect = somefunction_i_dont_control(letters,26); if( (suspect >= letters) && (suspect < do_not_read) ) printf("%c", suspect); 



Another edit, after reading AndreyT's answer, seems correct. So I will do something like this:

 char letters[26]; uintptr_t begin = letters; uintptr_t toofar = begin + sizeof(letters); char *suspect = somefunction_i_dont_control(letters,26); if( ((uintptr_t)suspect >= begin) && ((uintptr_t)suspect < toofar ) ) printf("%c", suspect); 


Thanks everyone!

+15
c comparison pointers
Jul 15 2018-11-11T00
source share
5 answers

A comparison of pointers cannot be signed or not signed. Pointers are not integers.

The C language (like C ++) defines relative pointer comparisons only for pointers that point to the same aggregate (structure or array). The order is natural: a pointer that points to an element with a lower index in the array is smaller. A pointer that points to a previously declared member of the structure is smaller. It.

You cannot legally compare arbitrary pointers in C / C ++. The result of this comparison is not defined. If you are interested in comparing the numerical values ​​of addresses stored in pointers, you must first manually convert the pointers to integer values. In this case, you have to decide whether to use an integer type with intptr_t or unsigned ( intptr_t or uintptr_t ). Depending on which type you choose, the comparison will be “signed” or “unsigned”.

+23
Jul 15 2018-11-11T00:
source share

The conversion of integers to a pointer is completely defined, so it depends on the implementation used.

However, you are allowed to relationally compare pointers pointing to parts of the same object (basically, sub-objects of the same structure or elements of the same array). You are not allowed to compare two pointers to arbitrary, completely unrelated objects.

+8
Jul 15 '11 at 2:45
source share

From the C ++ Standard 5.9 project:

If two pointers p and q the same type point to different objects that are not members of the same object or elements of the same array or to different functions, or if only one of them is zero, the results from p<q , p>q , p<=q and p>=q not defined.

So, if you throw numbers on pointers and compare them, C ++ gives unspecified results. If you take the address of elements that you can compare, the results of the comparison operations are indicated regardless of the subscription of pointer types.

Note unspecified is not undefined: it is quite possible to compare pointers to different objects of the same type that are not in the same structure or array, and you can expect some self-consistent result (otherwise it would be impossible to use pointers such as keys in trees, or sort vector such pointers, binary search of a vector, etc., where a consistent, intuitive general order is required < ).

Note that in very old C ++ standards, the behavior was undefined - like the 2005 draft WG14 / N1124 and edrewdski links under James McNellis answer -

+4
Jul 15 2018-11-11T00:
source share

I know that several answers here say that you cannot compare pointers unless they point to the same structure, but that the red herring, and I will try to explain why. One of your pointers points to the beginning of your array, and the other points to the end, so they point to the same structure. A language attorney may say that if your third pointer points outside the object, the comparison is undefined, so x >= array.start may be true for all x . But this is not a problem, since at the time of comparison C ++ cannot know if the array is built into an even larger structure. Also, if your address space is linear, as it is today, a pointer comparison will be implemented as an (un) signed integer comparison, since any other implementation will be slower. Even during periods of segments and offsets, a comparison (far) pointer was implemented by first normalizing the pointer and then comparing them as integers.

What it all boils down to is that if your compiler is fine, comparing pointers without worrying about signs should work if all you care about is that the pointer points inside the array, since the compiler needs to make pointers signed or unsigned, depending on which of the two borders a C ++ object can have.

Different platforms behave differently in this matter, so C ++ should leave it on the platform. There are even platforms in which both addresses around 0 and 80..00h cannot be displayed or are already accepted at the start of the process. In this case, it does not matter if you agree on this.

This can sometimes cause compatibility issues. For example, there is no sign in Win32 pointers. Now it was so that for the 4 GB address space for applications only the lower half was available (more precisely 10000h ... 7FFFFFFFh due to the destination section of the NULL pointer); high addresses were available only to the kernel. This forced some people to put the addresses in the signed variables, and their programs continued to work, since the high bit was always 0. But then the /3GB switch appeared, which made almost 3 GB available for applications (more precisely 10000h ... BFFFFFFFh) and the application would crumble or behave randomly.

You expressly declare that your program will be for Windows only, which uses unsigned pointers. However, you may change your mind in the future, and using intptr_t or uintptr_t bad for portability. I also wonder if this should be done at all ... if you are indexing into an array, it may be safer to compare indexes. Suppose, for example, that you have an array of 1 GB at 1500000h ... 41500000h, consisting of 16 384 elements of 64 kB each. Suppose you accidentally looked at the 80,000 index - clearly out of reach. Computing the pointer will give 39D00000h, so your check of the pointer will allow this, although it should not.

0
Nov 17 '15 at 8:01
source share

To complement other answers, comparisons between pointers that point to different objects depend on the standard.

In C99 (ISO / IEC 9899: 1999 (E)), §6.5.8:

5 [...] In all other cases, the behavior is not defined .

In C ++ 03 (ISO / IEC 14882: 2003 (E)), §5.9:

-Other pointer comparisons not defined .

0
Feb 27 '19 at 8:08
source share



All Articles