Pointer manipulation in C - c

I am new to C programming. While solving one of my class assignments, I came across the following code snippet. I did not understand what it does.
Can any one tell me what is the meaning of following C syntax,
((char *)0 +1) or ((int*)0 +1))

The (char *) 0 part creates a pointer to character data, at address 0. This address is then incremented by one, triggering undefined behavior since pointers to address 0 (also known as NULL in C) cannot be used in pointer arithmetic. The second part does the same but for pointer to integer data.
If the compiler simply treats NULL as the address (which is common but, again, not required which is why this is undefined behavior) the resulting addresses, if viewed numerically, will not be the same, since pointer arithmetic in C is done in terms of the type being pointed at, and typically sizeof (int) > sizeof (char).

Can any one tell me what is the meaning of following C syntax,
((char *)0 +1) or ((int*)0 +1))
Nothing by the terms of the C standard, because it's not defined. This code invokes undefined behavior on part of the C compiler. Let me explain:
In C every pointer may either point to some object of the type the pointer dereferences to or it may be 0, which is then called a null pointer. Null pointers can not be used in →pointer arithmetic.
Note that the actual representation of a null pointer on the metal, i.e. the bits the variable has on the machine may be something different than all zeros. But on the C side of things the null pointer always compares equal to an integer of the value 0. Moreover null pointers of different types also compare equal by definition. However comparisons of non null pointers of different types invokes undefined behavior. Also you can cast any pointer to a void* pointer, and back. Also you can cast every pointer to an integer of type uintptr_t and back. But casting from a pointer to type A to a pointer of type B (where B is not void*) invokes undefined behavior.
The special function malloc is defined by the C language specification to return a void* pointer that can be cast to any pointer type, though. But say you use it to allocate some memory for an array of char and later you cast that to int this again invokes undefined behavior.
Now you may ask: "What is undefined behavior?". Well, it just means, that the language standard doesn't define it and an implementer may go about it in any way seen fit. On most plattforms writing something like ((char*)0 + 1) may do something naively expected (creating a pointer, pointing to address 1), but it may as well make the compiler build an artificial intelligence, that at first chases you down the street, then gains consciousness and finally takes over the world, turning humans into batteries. So be careful about what you do ;)

In C you have to tell compiler which type you mean to use, this is called "casting".
For example:
char *c; //define c as "char pointer" (pointer to char)
c = ((char *)0 + 1); //this casts "0 + 1" to "char pointer" type, in this example not strictly necessary but adds some clarification to code

Related

If a pointer to pointer is NULL, then is it necessary that the pointer is also NULL?

Consider I have a structure
typedef struct point_t
{
int x;
int y;
}POINT;
I create a pointer to pointer for POINT and initialize it to NULL.
POINT **ppPoint = NULL;
Should *ppPoint also return NULL ?
The fact that there are 2 layers of pointers here is actually irrelevant. The fact that your outer pointer in NULL means it is illegal to dereference it. Therefore it is not meaningful to ask what value you would get by dereferencing it.
Consider this:
int *p = NULL; // modern practice would be to use nullptr anyway
if (0 == *p) // this is Undefined Behaviour!
{
// do something, maybe?
}
You are just adding another layer to this, where instead of int, you have point_t*, but it really makes no difference.
The thing with Undefined Behaviour is that anything can happen! Your program might crash, or it might appear to work, or it might give you garbage values sometimes, or it might ...
A null pointer does not point to anything. That applies to ordinary pointers, function pointers and member pointers alike. It also applies to pointers to pointers.
Therefore, it doesn't make sense to talk about the value of "what it points to".
You can't dereference a pointer which has a value of NULL. So you won't be able to access *ppPoint.
You can check the address of a variable with the %p formater in a printf() to check.
printf("Address of ppPoint: %p", *ppPoint);
printf("Address of *ppPoint: %p", *ppPoint);
First, there's the usual misconceptions about the mysterious null. In this case there's 3 related terms:
null pointer
null pointer constant
The NULL macro
A null pointer constant is the integer 0 or that integer cast to a pointer, (void*)0. The NULL macro is guaranteed to be a portable null pointer constant.
Whenever you assign a null pointer constant, such as NULL, to any pointer, that pointer becomes a null pointer. This allows compilers to internally represent a null pointer as something else than 0, because the address 0x00...00 is quite often a valid physical address on many systems.
Specifically, C17 6.3.2.3/3 defines this:
An integer constant expression with the value 0, or such an expression cast to type
void *, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.
When accessing a null pointer by de-referencing it, with don't get any predictable result. This is undefined behavior as per C17 6.5.3.2/4:
If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined.
Meaning anything can happen. If you are lucky, you just get a system crash.
You can however compare a null pointer against another null pointer, or against a null pointer constant, and they are guaranteed to be equal (C17 6.5.9).
As for pointer-to-pointer being some a special case, it is not. The pointed-at type is irrelevant for any of the above mentioned rules. Overall there is nothing special with pointer-to-pointer in C - it is never a special case, but always to be regarded as pointer-to-type.

Does C have more macros like NULL?

Background:
When deleting a cell in a hash table that uses linear probing you have to indicate that a value once existed at that cell but can be skipped during a search. The easiest way to solve this is to add another variable to store this information, but this extra variable can be avoided if an guaranteed invalid memory address is known and is used to represent this state.
Question:
I assume that since 0 is a guaranteed invalid memory address (more often than not), there must be more than just NULL. So my question is, does C provide a standard macro for any other guaranteed invalid memory addresses?
Technically, NULL is not guaranteed to be invalid. It is only guaranteed not to be the address of any object (C11 6.3.2.3:3):
An integer constant expression with the value 0, or such an expression
cast to type void *, is called a null pointer constant(66). If a null
pointer constant is converted to a pointer type, the resulting
pointer, called a null pointer, is guaranteed to compare unequal to a
pointer to any object or function.
(66) The macro NULL is defined in (and other headers) as a null pointer constant
Your usage does not require the special address value to be invalid either: obviously, you are not accessing it, unless segfaulting is part of the normal behavior of your program.
So you could use the addresses of as many objects as you like, as long as the addresses of these objects are not intended to be part of the normal contents of a cell.
For instance, for an architecture where converting between pointers to objects preserve the representation, you could use:
char a, b, …;
#define NULL1 (&a)
#define NULL2 (&b)
…
Strictly speaking, NULL is not required to be numerically zero at runtime. C translates 0 and NULL, in a pointer context, into an implementation-defined invalid address. That address is often numerically zero, but that is not guaranteed by the C standard. To the best of my knowledge, C itself does not provide any invalid addresses guaranteed to be distinct from NULL.
You can also create your own 'invalid' address pointer:
const void* const SOME_MARKER = (void*) &x;
If you make sure that x (or its address) can never be actually used where you want to use SOME_MARKER you should be safe and 100% portable.

Why this redefinition of sizeof works

I'm redefining sizeof as:
#undef sizeof
#define sizeof(type) ((char*)((type*)(0) + 1) - (char*)((type*)(0)))
For this to work, the 2 '0' in the definition need to be the same entity in memory, or in other words, need to have the same address. Is this always guaranteed, or is it compiler/architecture/run-time dependent?
The 0 here is not an object – it is an address. So the question you ask is something of a non-sequitur.
You are thinking that the zero's are discreet pieces of data that need to be stored somewhere. They aren't.. they are being cast as pointers to memory location zero.
When you increment a pointer to a type, it is actually incremented by the size of the type it points to. This is how C array arithmetic works.
In practice, a null pointer of a certain type always refers to the same location in memory (especially when constructed the same way, as you do above), simply because any other implementation would be senseless.
However, The standard actually does not guarantee a lot about this:
"[...] is guaranteed to compare unequal to a pointer to any object or function." 6.3.2.3§3
"[...] Any two null pointers shall compare equal." 6.3.2.3§4
This leaves a lot of lee-way. Assume a memory model with two distinctive regions. Each region could have a region of null pointers (say the first 128 bytes). It is easy to see, that even in that weird case, the basic assumptions about null pointers can indeed hold! Well, given a proper compiler that makes weird null tests...
So, what else do we know about pointers in general...
What you are trying to do is first, increment a pointer
"one operand shall be a pointer to a complete object type and the other shall have integer type. (Incrementing is equivalent to adding 1.)" [6.5.6§2]
and then a pointer difference
"both operands are pointers to qualified or unqualified versions of compatible complete object types" [6.5.6§3]
OK, they are (well, assuming type is a complete object type). But what about semantics?
"For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type." [6.5.6§7]
This is actually a bit of a problem: The null pointer need not point to an actual object! (Otherwise you could dereference it safely...) Therefore, incrementing it or subtracting it from another pointer is UB!
To conclude: 0 does not point to an object, and therefore the answer to your question is No.
A strictly standards-conforming compiler could reject this, or return some nonsense. On "typical" machines and pointers have the same size, and casting an integer to a pointer just takes that bit pattern and looks at it as a pointer. There are machines where words contain extra data (type perhaps, permission bits). Some addresses might be forbidden for certain objects (i.e., nothing can have address 0), and so on. While it is guaranteed that sizeof(char) == 1, on e.g. Crays a character is actually 32 bits.
Besides, the C standard guarantees that the expresison in sizeof(expression) is not evaluated at all, just its type is taken. I.e., ^sizeof(x++)doesn't incrementx`.

Is NULL in C required/defined to be zero?

NULL appears to be zero in my GCC test programs, but wikipedia says that NULL is only required to point to unaddressable memory.
Do any compilers make NULL non-zero? I'm curious whether if (ptr == NULL) is better practice than if (!ptr).
NULL is guaranteed to be zero, perhaps casted to (void *)1.
C99, §6.3.2.3, ¶3
An integer constant expression with the value 0, or such an expression cast to type
void *, is called a null pointer constant.(55) If a null pointer constant is converted to a
pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal
to a pointer to any object or function.
And note 55 says:
55) The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant.
Notice that, because of how the rules for null pointers are formulated, the value you use to assign/compare null pointers is guaranteed to be zero, but the bit pattern actually stored inside the pointer can be any other thing (but AFAIK only few very esoteric platforms exploited this fact, and this should not be a problem anyway since to "see" the underlying bit pattern you should go into UB-land anyway).
So, as far as the standard is concerned, the two forms are equivalent (!ptr is equivalent to ptr==0 due to §6.5.3.3 ¶5, and ptr==0 is equivalent to ptr==NULL); if(!ptr) is also quite idiomatic.
That being said, I usually write explicitly if(ptr==NULL) instead of if(!ptr) to make it extra clear that I'm checking a pointer for nullity instead of some boolean value.
Notice that in C++ the void * cast cannot be present due to the stricter implicit casting rules that would make the usage of such NULL cumbersome (you would have to explicitly convert it to the compared pointer's type every time).
From the language standard:
6.3.2.3 Pointers
...
3 An integer constant expression with the value 0, or such an expression cast to type
void *, is called a null pointer constant.55) If a null pointer constant is converted to a
pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal
to a pointer to any object or function.
...
55) The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant; see 7.17.
Given that language, the macro NULL should evaluate to a zero-valued expression (either an undecorated literal 0, an expression like (void *) 0, or another macro or expression that ultimately evaluates to 0). The expressions ptr == NULL and !ptr should be equivalent. The second form tends to be more idiomatic C code.
Note that the null pointer value doesn't have to be 0. The underlying implementation may use any value it wants to represent a null pointer. As far as your source code is concerned, however, a zero-valued pointer expression represents a null pointer.
In practice is the same, but NULL is different to zero. Since zero means there's a value and NULL means there isn't any. So, theoretically they are different, NULL having a different meaning and in some cases that difference should be of some use.
in practice no, !ptr is correct

Issue with NULL pointers on Harvard Architecture platform

Interesting issue we came across here this week.
We are working in C on a Harvard Architecture embedded platform, which has 16-bit data addresses and 32-bit code addresses.
The issue occurs when you are working with function pointers. If you have code like
if (fp) fp();
or
if (fp != 0) fp();
everything is fine.
However if you have code like
if (fp != NULL) fp();
then, because NULL is defined as (void *) 0, the compiler (gcc in this case) a) does not warn and b) does a 16-bit comparison against your function pointer instead of a 32-bit comparison. Fine as long as your function pointer doesn't happen to lie on a 64k boundary so all bottom 16 bits are 0.
At the moment we have large swathes of code which contain explicit checks against NULL. Most of them will be data pointers, but some of them will be function pointers. A quick grep for != NULL or == NULL revealed over 3000 results, to many to go through manually to check.
So, what we would like now would be either
a way to find all the cases where function pointers (but not data pointers) are compared (so we can instead have them compare against FP_NULL which we would define as a 32-bit 0), or
to redefine NULL in such a way that it would do the right thing.
(Or, I suppose, to
update our gcc port to detect and
correctly handle this case).
I can't think of any approach that works for 1. The only approach I can think of for 2 is to redefine NULL as a 0 function pointer, which would be very wasteful for the vast majority of comparisons which are against data pointers. (A 32-bit compare is 4 instructions, a 16-bit compare is 1 instruction).
Any thoughts or suggestions?
It seems to me the easiest way is replace all occurrences of NULL by 0. This works for function pointer (as you say) and object pointers.
This is a variant of (2) Redefine NULL to plain 0.
But the fact that you cannot compare function pointers with NULL is a bug in your implementation. C99 states that comparison of the null pointer constant is possible with both object and function pointers, and that NULL should expand to this constant.
Small addition from the C-FAQ question 5.8:
Q: Is NULL valid for pointers to functions?
A: Yes (but see question 4.13)
Mixing function pointers with (void *) 0
(A reply to R..'s comment). I believe using function pointers and (void *) 0 together is well-defined. In my reasoning I will refer to sections of the C99 draft 1256, but will not quote large parts to keep it readable. It should also be applicable to C89.
6.3.2.3 (3) defines the integer constant expression 0 and such an expressions cast to (void *) as null pointer constant. And: "If a null pointer constant is converted to a
pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal
to a pointer to any object or function."
6.8.9 defines the == and != operands for (among other) a pointer operand and a null pointer constant. For these: "If one operand is a pointer and the other is a
null pointer constant, the null pointer constant is converted to the type of the pointer."
Conclusion: In fp == (void *) 0, the null pointer constant is converted to the type of fp. This null pointer can be compared to fp and is guaranteed to be unequal to fp if it points to a function. Assignment (=) has a similar clause, so fp = (void *) 0; is also well-defined C.
The way you describe should work:
6.3.2.3/3 An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.
So, either NULL has been redefined to something not 0 or (void*)0 (or equivalent?) or your compiler is non-conformant.
Try redefining NULL yourself (to plain 0) after all the #includes in all files :-)
just for kicks: try gcc -E (to output the preprocessed source) on a problem file and check the expansion of NULL
You could try this:
#ifdef NULL
#undef NULL
#endif
#define NULL 0
Here are a few suggestions:
temporarily change NULL to (char*)0 or something else that is not implicitly convertible to a function pointer. This should give a warning about every comparison with a non-matching pointer. You could then run the produced compiler output through a tool like grep and look for a typical pattern for function pointers, like (*)(.
redefine NULL as 0 (without the cast to void*). This is another valid definition for NULL and might do the right thing for you, but no guarantees.
You could try a segment hack (really only a hack), so you can use the fast 16bit comparision, without any risk.
Create segements at each n*0x10000 boundary with size of 4 (or even smaller), so there never can't exists a real function.
It depends on your embedded device memory space, if this is a good or a really bad solution.
It could work if you have 1MB normal Flash, which will never change.
It will be painfull if you have 64MB Nand Flash.
Edit the implemention's system headers to replace all occurrances of
#define NULL ((void *)0)
with
#define NULL 0
Then file a bug report with the vendor. You should not have to modify your (perfectly correct, albeit ugly style) code because of a bug in the vendor's compiler.

Resources