Whats the difference between int *p=10 and int *p = (int *)10? - c

Do both statements mean the same thing that p is pointing at address location 10?
On compilation, the first initialization gives some warning. What's the meaning of that?
#include <stdio.h>
int main()
{
int *p = 10;
int *q = (int *)10;
return 0;
}
output:
warning: initialization of ‘int *’ from ‘int’ makes pointer from integer without a cast [- Wint-conversion]

Both cases convert the integer 10 to a pointer type which is used to initialize an int *. The cast in the second case makes it explicit that this behavior is intentional.
While converting from an integer to pointer is allowed, the assignment operator (and by extension, initialization) does not specifically allow this conversion, so a cast it required to be conforming. Many compilers however will still allow this and simply issue a warning (as your apparently does).
Note however that actually attempting to use a pointer that is assigned a specific numeric value will most likely cause a crash unless you're on a embedded system that supports reading or writing specific memory addresses.

int *p = 10; is incorrect (constraint violation), and the compiler must produce a diagnostic message. The compiler could reject the program, and there is no behaviour defined if it doesn't. The rule is that the initializer for a pointer must be a compatible pointer value or a null pointer constant.
int *q = (int *)10; means to convert the integer 10 to a pointer. The result is implementation-defined and it could be a trap representation, meaning that the initialization causes undefined behaviour if execution reaches this line.

int and pointer to an integer int* are different types. The 10 on the first line is an int that you are trying to assign to a pointer to int type. Hence the warning. (on X86 both share the same size, but consider that mostly coincidence at this point).
By casting the int to a pointer, like you do on the second line, you are telling the compiler "Hey, I know these are different types but I know what I'm doing, so go ahead and just treat the value 10 like a pointer because I really do want to point at the memory with an address of 10". (in almost every case the memory address of 10 is not going to be usable by you)

Related

Why do I get warnings when I try to assign the address of a variable to a pointer that was declared to point to a variable of a different type?

Take a look at the following program. What I don't understand is why do I have to cast the address of the variable x to char* when it actually would be absolutely useless if you think about it for a second. All I really need is only the address of the variable and all the necessary type information is already in place provided by the declaration statement char* ptr.
#include <stdio.h>
int main(void) {
int x = 0x01020309;
char* ptr = &x; /* The GCC compiler is going to complain here. It will
say the following: "warning: initialization from
incompatible pointer type [enabled by default]". I
need to use the cast operator (char*) to make the
compiler happy. But why? */
/* char* ptr = (char*) &x; */ /* this will make the compiler happy */
printf("%d\n", *ptr); /* Will print 9 on a little-endian machine */
return 0;
}
The C Standard, 6.2.5 Types, paragraph 28 states:
A pointer to void shall have the same representation and
alignment requirements as a pointer to a character type.
Similarly, pointers to qualified or unqualified versions of
compatible types shall have the same representation and
alignment requirements. All pointers to structure types shall have
the same representation and alignment requirements as each other.
All pointers to union types shall have the same
representation and alignment requirements as each other.
Pointers to other types need not have the same representation or alignment requirements.
Since different types of pointers can have differing implementations or constraints, you can't assume it's safe to convert from one type to another.
For example:
char a;
int *p = &a
If the implementation has an alignment restriction on int, but not on char, that would result in a program that could fail to run.
This is because pointers of different types point to blocks of memory of different sizes even if they point to the same location.
&x is of type int* which tells the compiler the number of bytes (depending on sizeof(int)) to read when getting data.
Printing *(&x) will return the original value you entered for x
Now if you just do char* ptr = &x; the compiler assigns the address in &x to your new pointer (it can as they are both pointers) but it warns you that you are changing the size of the block of memory being addressed as a char is only 1 byte. If you cast it you are telling the compiler that this is what you intend.
Printing *(ptr) will return only the first byte of the value of x.
You are correct that it makes no practical difference. The warning is there to inform you that there might be something fishy with that assignment.
C has fairly strong type-checking, so most compilers will issue a warning when the types are not compatible.
You can get rid of the warning by adding an explicit cast (char*), which is you saying:
I know what I'm doing, I want to assign this value to my char* pointer even if the types don't match.
Its just simple as you assign integer type to character. similarly you are trying to assign integer type pointer to character type pointer.
Now why is so because this is how c works, if you increment a character pointer it will give you one byte next address and incrementing integer pointer will give you 2 byte next address.
According to your code, x is of type int. So the pointer that points to x should be of type int *. Compiler gives such error because you use a pointer which is not int *.
So make your pointer either int *, or void * then you don't need cast.

Why typecasting between char *ptr to int and int *ptr to char works completely fine? when they are designed to point to specific datatyped variables

I have just started learning pointers. I have some questions regarding pointers typecasting. Consider below program.
int main(){
int a = 0xff01;
char *s = &a;
char *t = (int *) &a;
printf("%x",*(int *)s);
printf(" %x",*(int *)t);
return 0;
}
The statement char *s = &a gives
warning: incompatible pointer conversion type.
But noticed that the two printf() statements works fine they give me the right output. The question is
char *t , char *s both are pointers to character type.
Why does 'C' compilers lets me to assign integer variable to char *p ? why dont they raise an error and restrict the programmer?
We have int *ptr to point to integer variables, then why do they still allow programmer to make char *ptr point to integer variable?
// Another sample code
char s = 0x02;
int *ptr = (char *)&s;
printf("%x",*(char *)ptr); // prints the right output
Why does an int *ptr made point to character type? it works. why compiler dont restrict me?
I really think this leads me to confusion. If the pointer types are interchangeable with a typecast then what is the point to have two different pointers char *ptr , int *ptr ?
when we could retrieve values using (int *) or (char *).
All pointers are of same size 4bytes(on 32bite machine). Then one could use void pointer.
Yes people told me, void pointers always needs typecasting when retrieving values from memory. When we know the type of variable we go for that specific pointer which eliminates the use of casting.
int a = 0x04;
int *ptr = &a;
void *p = &a;
printf("%x",*ptr); // does not require typecasting.
printf("%x",*(int *)p); // requires typecasting.
Yes, I have read that back in old days char *ptrs played role of void pointers. Is this one good reason? why still compilers support typecasting between pointers? Any help is greatly appreciated.
Compiling with GCC 4.9.1 on Mac OS X 10.9.5, using this mildly modified version of your code (different definition of main() so it compiles with my preferred compiler options, and included <stdio.h> which I assume was omitted for brevity in the question — nothing critical) in file ptr.c:
#include <stdio.h>
int main(void)
{
int a = 0xff01;
char *s = &a;
char *t = (int *) &a;
printf("%x",*(int *)s);
printf(" %x",*(int *)t);
return 0;
}
I get the compilation errors:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition -Werror ptr.c -o ptr
ptr.c: In function ‘main’:
ptr.c:6:15: error: initialization from incompatible pointer type [-Werror]
char *s = &a;
^
ptr.c:7:14: error: initialization from incompatible pointer type [-Werror]
char *t = (int *) &a;
^
cc1: all warnings being treated as errors
$
So, both assignments are the source of a warning; my compilation options turn that into an error.
All pointers other than void * are typed; they point to an object of a particular type. Void pointers don't point to any type of object and must be cast to a type before they can be dereferenced.
In particular, char * and int * point to different types of data, and even when they hold the same address, they are not the same pointer. Under normal circumstances (most systems, most compilers — but there are probably exceptions if you work hard enough, but you're unlikely to be running into one of them)…as I was saying, under normal circumstances, the types char * and int * are not compatible because they point to different types.
Given:
int data = 0xFF01;
int *ip = &data;
char *cp = (char *)&data;
the code would compile without complaint. The int data line is clearly unexceptional (unless you happen to have 16-bit int types — but I will assume 32-bit systems). The int *ip line assigns the address of data to ip; that is assigning a pointer to int to a pointer to int, so no cast is necessary.
The char *cp line forces the compiler's hand to treat the address of data as a char pointer. On most modern systems, the value in cp is the same as the value in ip. On the system I learned C on (ICL Perq), the value of a char * address to a memory location was different from the 'anything else pointer' address to the same memory location. The machine was word-oriented, and byte-aligned addresses had extra bits set in the high end of the address. (This was in the days when the expansion of memory from 1 MiB to 2 MiB made a vast improvement because 750 KiB were used by the O/S, so we actually got about 5 times as much memory after as before for programs to use! Gigabytes and gibibytes were both fantasies, whether for disk or memory.)
Your code is:
int a = 0xff01;
char *s = &a;
char *t = (int *) &a;
Both the assignments have an int * on the RHS. The cast in the second line is superfluous; the type of &a is int * both before and after the cast. Assigning an int * to a char * is a warnable offense — hence the compiler warned. The types are different. Had you written char *t = (char *)&a;, then you would have gotten no warning from the compiler.
The printing code works because you take the char * values that were assigned to s and t and convert them back to the original int * before dereferencing them. This will usually work; the standard guarantees it for conversions to void * (instead of char *), but in practice it will normally work for anything * where anything is an object type, not a function type. (You are not guaranteed to be able to convert function pointers to data pointers and back again.)
The statement char *s = &a gives
warning: incompatible pointer conversion type.
In this case, the warning indicates a constraint violation: A compiler must complain and may refuse to compile. For initialization (btw, a declaration is not a statement), the same conversion rules as for assignment apply, and there is no implicit conversion from int * to char * (or the other way round). That is, an explicit cast is required:
char *s = (char *)&a;
Why do C compilers let me assign an integer variable to char *p? Why don’t they raise an error and restrict the programmer?
Well, you’ve got a warning. At the very least, a warning means you must understand why it is there before you ignore it. And as said above, in this case a compiler may refuse to compile.*)
We have int *ptr to point to integer variables, then why do they still allow programmer to make char *ptr point to integer variable?
Pointers to a character type are special, they are allowed to point to objects of every type. That you’re allowed to do so, doesn’t mean it’s a good idea, the cast is required to keep you from doing such a conversion accidently. For pointer-to-pointer conversions in general, see below.
int *ptr = (char *)&s;
Here, ptr is of type int *, and is initialized with a value of type char *. This is, again, a constraint violation.
printf("%x",*(char *)ptr); // prints the right output
If a conversion from a pointer to another is valid, the conversion back also is and always yields the original value.
If the pointer types are interchangeable with a typecast then what is the point to have two different pointers char *ptr, int *ptr?
Types exist to save you from errors. Casts exist to give you a way to tell the compiler that you know what you’re doing.
All pointers are of same size 4bytes(on 32bite machine). Then one could use void pointer.
That’s true for many architectures, but quite not for all the C standard addresses. Having only void pointers would be pretty useless, as you cannot really do anything with them: no arithmetic, no dereferencing.
Yes, I have read that back in old days char *ptrs played role of void pointers. Is this one good reason?
Perhaps a reason. (If a good one, is another question…)
When pointer-to-pointer conversions are allowed:
C11 (N1570) 6.3.2.3 p7
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned×) for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer. When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object.
×) In general, the concept “correctly aligned” is transitive: if a pointer to type A is correctly aligned for a pointer to type B, which in turn is correctly aligned for a pointer to type C, then a pointer to type A is correctly aligned for a pointer to type C.
Pointers to character types and pointers to void, as mentioned above, are always correctly aligned (and so are int8_t and uint8_t if they exist). There are platforms, on which a conversion from an arbitrary char pointer to an int pointer may violate alignment restrictions and cause a crash if executed.
If a converted pointer satisfies alignment requirements, this does not imply that it’s allowed to dereference that pointer, the only guarantee is that it’s allowed to convert it back to what it originally pointed to. For more information, look for strict-aliasing; in short, this means you’re not allowed to access an object with an expression of the wrong type, the only exception being the character types.
*) I don’t know the reasons in your particular case, but as an example, where it’s useful to give implementations such latitude in how to treat ill-formed programmes, see for example object-pointer-to-function-pointer conversions: They are a constraint violation (so they require a diagnostic message from the compiler) but are valid on POSIX systems (which guarantess well-defined semantics for such conversions). If the C standard required a conforming implementation to abort compilation, POSIX had to contradict ISO C (cf. POSIX dlsym for an example why these conversions can be useful), which it explicitly doesn’t intend to.
Pointers are not having any types, types described with pointer in program actually means that to which kind of data pointer is pointing. Pointers will be of same size.
When you write,
char *ptr;
it means that is is pointer to character type data and when dereferenced, it will fetch one bytes data from memory
Similarly,
double *ptr;
is pointer to double type data. So when you dereference, they will fetch 8 bytes starting from the location pointed by pointer.
Now remember that all the pointer are of 4 bytes on 32 bit machines irrespective of the type of data to which it is pointing. So if you store integer variable's address to a pointer which is pointing to character, it is completely legal and if you dereference it, it will get only one byte from memory. That is lowest byte of integer on little endian pc and highest byte of integer on big endian pc.
Now you are type casting your pointer to int type explicitly. So while dereferencing it will get while integer and print it. There is nothing wrong with this and this is how pointers work in c.
In your second example you are doing the same. Assigning address of character type variable to pointer which is pointing to integer. Again you are type casting pointer to character type so by dereference it will get only one byte from that location which is your character.
And frankly speaking, i dont know any practical usage of void pointer but as far as i know, void pointers are used when many type of data is to be dereferenced using a single pointer.
Consider that you want to store an integer variable's address to pointer. So you will declare pointer of integer type. Now later in program there is a need to store a double variable's address to pointer. So instead of declaring a new pointer you store its address in int type pointer then if you dereference using it, there will be a big problem and result in logical error which may get unnoticed by you if you have forgot to type cast it to double type. This is not case with void pointer. If you use void pointer, you have to compulsarily type cast it to particular type inorder to fetch data from memory. Otherwise compiler will show error. So in such cases using void pointer reminds you that you have to type cast it to proper type every time otherwise compiler will show you error. But no error will be shown in previous case

Pointer conversions

I read that assigning a pointer to a type to another pointer to another type is illegal; for example, in this book:
C How To Program 7 ed. pag. 299
Common Programming Error 7.7
Assigning a pointer of one type to a
pointer of another type if neither is of type void * is a syntax
error.
or at this URL:
but hower in the C11 standard is written:
A pointer to an object type may be converted to a pointer to a
different object type. If the resulting pointer is not correctly
aligned for the referenced type, the behavior is undefined.
Otherwise, when converted back again, the result shall compare equal
to the original pointer.
So I understand that only if there is an alignment problem the behavior is undefined.
In fact compilers like GCC 4.8 or cl 2013 emits only a warning of assignment from incompatible pointer type.
That exception is not present for void pointer.
So:
int a = 10;
float b = 100.22f;
int *p_a = &a;
float *p_f = &b;
p_a = p_f; // NOT ILLEGAL but WARNING
p_f = p_a; // converted back again. it still works
void *v_p = p_a; // NOT ILLEGAL NO WARNING
p_a = v_p; // converted back again. it still works
Do I understand well? Or Am I missing something?
P.S.
Can also anyone show me an example of an "alignment problem"?
You can consider a pointer to be an offset in memory to pointed data, and no matter what type it is. Any standard pointer (not smart ones) has fixed size, depending on system (32 bit or 64). So you can assign them each to other, modern compiler will warn you about dangerous operations, BUT problem is when you try to dereference pointer of incompaitable type. When dereferencing, app looks up the number of bytes corresponding to pointed type, so in next example
int b = 10;
int* pB = &b;
double* pA = pB;
on dereference pB you will get 10 (size of int is 4 bytes), and on dereference pA you will get trash or crash because next 4 bytes (double is 8 bytes) can be memory space allocated for another variable.
Conclusion: keep track of pointer types when assigning them to each others and especially if you assign them indirectly, using void* as intermediary.
Legality or illegality of pointer assignment is compiler's matter, the old ones didn't warn you. Assigning to void* is not considered "illegal" maybe because it is generic, unreferencable pointer type (it has undefined referencing size and that restriction is c language restriction), so you can't receive error like in example above.

Can int store the base address of string in C?

Why do the code run without error ?
#include <stdio.h>
int main() {
int i="string"; //the base of string can be stored in a character pointer
printf("%s\n",i);
printf("%d",i);
return 0;
}
//compiling on ideone.com language c
OUTPUT:
string
134513984 //some garbage(address of "string")
Please explain if there is some flexibility in the pointer in c. I tried it for c++ which gives error: cannot convert ‘const char*’ to ‘int*’ in initialization
No, you cannot assume this in general. In part, this is because int may not be the same size as char * (in fact, on many 64-bit compilers it will not be the same size).
If you want to store a pointer as an integer, the appropriate type to use is actually intptr_t, from <stdint.h>. This is an integer which is guaranteed to be able to hold a pointer's value.
However, the circumstances when you'd actually want to do this are somewhat rare, and when you do do this you should also include an explicit cast:
intptr_t i=(intptr_t)"string"; //the base of string can be stored in a character pointer
This also complicates printing its value, you'll need to use a macro to be portable:
printf("%"PRIiPTR,i);
To print the original string, you should also cast:
printf("%s", (char *)i);
In general, no: the C standard states that conversions from pointers to integers are implementation defined. Further, this can be problematic on systems where sizeof(char *) and sizeof(int) are different (i.e. x86-64), for two reasons:
int i = "string"; can lose information, if the e.g. 64-bit pointer cannot fit in a 32-bit integer.
printf expects a pointer to be passed in, but gets a smaller integer. It winds up reading some garbage into the full pointer, and can crash your code (or worse).
Often times, however, compilers are "smart" enough to "fix" arguments to printf. Further, you seem to be running on a platform where pointers and integers are the same size, so you got lucky.
If you compiled this program with warnings (which you should) you'd get the following complaints:
main.c:3:9: warning: incompatible pointer to integer conversion initializing 'int' with an expression of type 'char [7]' [-Wint-conversion]
int i="string"; //the base of string can be stored in a character pointer
^ ~~~~~~~~
main.c:4:19: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
printf("%s\n",i);
~~ ^
%d
2 warnings generated.
Warnings generally mean you're doing something that could cause unexpected results.
Most C compilers will let you do this, but that doesn't make it a good idea. Here, the address of the character array "string" gets stored in i. The printf options are determining how the integer is interpreted (as an address or an integer). This can be problematic when char* is not the same size as an int (e.g. on most 64 bit machines).
The C++ compiler is more picky and won't let you compile code like this. C compilers are much more willing, although they will usually generate warnings letting the programmer know it is a bad idea.
Your code is ill-formed in both C and C++. It is illegal to do
int i = "string";
in both languages. In both languages conversion from a pointer to an integer requires an explicit cast.
The only reason your C compiler accepted it is that it was configured by default for rather loose error checking. (A rather typical situation with C compilers.) Tighten up your C compiler settings and it should issue an error for the above initialization. I.e. you can use an explicit conversion
int i = (int) "string";
with implementation-dependent results, but you can't legally do it implicitly.
In any case, the warning your compiler emitted for the above initialization is already a sufficient form of a diagnostic message for this violation.

c programming: what is the difference of the type conversions?

Given the following C code, what is the difference between a = f; and a = (int *) f;?
float *f;
int *a;
...
a = f;
a = (int *) f;
float *f;
int *a;
a = f;
This assignment is erroneous (there is a C constraint violation), there is no implicit conversion between pointer types (except with void *). A compiler can refuse to compile a program with this assignment.
Given:
float *f;
int *a;
This:
a = f;
is a constraint violation. It requires a diagnostic from any conforming compiler. After issuing the required diagnostic, it may or may not reject the program. (IMHO it should do so.) A conforming compiler may choose to accept it with a mere warning (which qualifies as a diagnostic), but once it does so the behavior of the program is undefined. Compilers that do this most commonly generate an implicit conversion from float* to int*, giving the same behavior as if there were a cast (an explicit conversion), but the standard does not require that.
Non-conforming compilers, of course are free to do anything they like.
Conclusion: Don't write code like that. Even if your compiler lets you get away with it, another compiler might not. If you want to convert from one pointer type to another, use a cast. Aside from validity issues, the cast makes it much clearer to the reader that something funny is going on. If your compiler gave you a warning, heed it. If it didn't, find out how to increase the warning levels on your compiler.
This:
a = (int *) f;
takes the value of f (which is of type float*) and explicitly converts it to type int*, then assigns that int* value to a. (I'll assume that something between the declaration and the assignment has set f to some valid value.)
If f is a null pointer, the conversion is well defined, and yields a null pointer of type int*. The rules for converting a non-null object pointer to another pointer type are (quoting N1570 6.3.2.3p7):
A pointer to an object type may be converted to a pointer to a
different object type. If the resulting pointer is not correctly
aligned for the referenced type, the behavior is undefined.
Otherwise, when converted back again, the result shall compare equal
to the original pointer.
This kind of conversion, assuming int and float are the same size and have similar alignment requirements, is likely intended to let you treat a float object as if it were an int object. This is called "type-punning". If int and float aren't the same size, or if they have different alignment requirements, this can easily blow up in your face, crashing your program (if you're lucky) or giving you garbage results (if you're not). (Yes, crashing the program is a good outcome; it lets you know there's a problem.)
If you really need to do that for some reason, it's better to define a union with int and float members, or to use memcpy() to copy the contents of a float object into an int object.
But it very rarely makes sense to do that kind of thing. If you want to examine the representation of a float object, it's better to treat it as an array of unsigned char something that the language standard explicitly permits.
6.5.16.1 Simple assignment
the left operand has atomic, qualified, or unqualified pointer type, and (considering
the type the left operand would have after lvalue conversion) both operands are
pointers to qualified or unqualified versions of compatible types, and the type pointed
to by the left has all the qualifiers of the type pointed to by the right.
So, a = f is a constraint violation and invokes undefined behavior.
In second case you are making f (by casting it)to be compatible to a's type. It is legal to do a casting in C (not sure about other languages).
But it should be noted that after casting f is still pointer to float and you have to cast it every time when you will assign it to a.
a = (int*) f; makes explicit that you want to cast a float* pointer to an int* pointer. Without it, you'll receive an incompatible pointer types error.
Your code will compile (at least in my linux and gcc). But you will get a warning.
If you use a = f; and then use a somewhere in your code, you will get erroneous data, because a float is stored in a different format in memory. Even if you do the casting first you probably will get erroneous results, but the compiler sees your casting and assumes you know what you are doing.
a = f; //assignment
// is a constraint violation
a = (int *) f; //cast + assignment
Explicitly casting float pointer to int pointer.simply hides compiler warnings or errors.
but very well might crash when running as the sizes of what the program expects when dereferencing the pointer differs from reality.

Resources