In this answer, the author discussed how it was possible to cast pointers in C. I wanted to try this out and constructed this code:
#include <stdio.h>
int main(void) {
char *c;
*c = 10;
int i = *(int*)(c);
printf("%d", i);
return 1;
}
This compiles (with a warning) and when I execute the binary it just outputs bus error: 10. I understand that a char is a smaller size than an int. I also understand from this post that I should expect this error. But I'd really appreciate if someone could clarify on what is going on here. In addition, I'd like to know if there is a correct way to cast the pointers and dereference the int pointer to get 10 (in this example). Thanks!
EDIT: To clarify my intent, if you are worried, I'm just trying to come up with a "working" example of pointer casting. This is just to show that this is allowed and might work in C.
c is uninitialized when you dereference it. That's undefined behaviour.
Likewise, even if c were initialized, your typecast of it to int * and then a dereference would get some number of extra bytes from memory, which is also undefined behaviour.
A working (safe) example that illustrates what you're trying:
int main(void)
{
int i = 10;
int *p = &i;
char c = *(char *)p;
printf("%d\n", c);
return 0;
}
This program will print 10 on a little-endian machine and 0 on a big-endian machine.
These lines of code are problematic. You are writing through a pointer that is uninitialized.
char *c;
*c = 10;
Change to something like this:
char * c = malloc (sizeof (char));
Then, the following line is invalid logic, and the compiler should at least warn you about this:
int i = *(int*)(c);
You are reading an int (probably 4 or 8 bytes) from a pointer that only has one byte of storage (sizeof (char)). You can't read an int worth of bytes from a char memory slot.
First of all your program has undefined behaviour because pointer c was not initialized.
As for the question then you may write simply
int i = *c;
printf("%d", i);
Integral types with rankes less than the rank of type int are promoted to type int in expressions.
I understand that a char is a smaller size than an int. I also understand from this post that I should expect this error. But I'd really appreciate if someone could clarify on what is going on here
Some architectures like SPARC and some MIPS requires strict alignment. Thus if you want to read or write for example a word, it has to be aligned on 4 bytes, e.g. its address is multiple of 4 or the CPU will raise an exception. Other architectures like x86 can handle unaligned access, but with performance cost.
Let's take your code, find all places where things go boom as well as the reason why, and do the minimum to fix them:
#include <stdio.h>
int main(void) {
char *c;
*c = 10;
The preceding line is Undefined Behavior (UB), because c does not point to at least one char-object. So, insert these two lines directly before:
char x;
c = &x;
Lets move on after that fix:
int i = *(int*)(c);
Now this line is bad too.
Let's make our life complicated by assuming you didn't mean the more reasonable implicit widening conversion; int i = c;:
If the implementation defines _Alignof(int) != 1, the cast invokes UB because x is potentially mis-aligned.
If the implementation defines sizeof(int) != 1, the dereferencing invokes UB, because we refer to memory which is not there.
Let's fix both possible issues by changing the lines defining x and assigning its address to c to this:
_Alignas(in) char x[sizeof(int)];
c = x;
Now, reading the dereferenced pointer causes UB, because we treat some memory as if it stored an object of type int, which is not true unless we copied one there from a valid int variable - treating both as buffers of characters - or we last stored an int there.
So, add a store before the read:
*(int*)c = 0;
Moving on...
printf("%d", i);
return 1;
}
To recap, the changed program:
#include <stdio.h>
int main(void) {
char *c;
_Alignas(in) char x[sizeof(int)];
c = x;
*c = 10;
*(int*)c = 0;
int i = *(int*)(c);
printf("%d", i);
return 1;
}
(Used the C11 standard for my fixes.)
Related
I am learning c in school , and having a little confusion on how to use type casting.
here is my code.
I am trying to figure out what type casting is and how it works.
I initialized a pointer(ptr3) that points the adress of k, then initialized ptr4 and assign ptr3 that is converted into int*.
but this does not seem like working, since it gives random values every time.
Why is it?
I appreciate any feedback ! thank you so much.
#include <stdio.h>
int main() {
char k = 10;
char* ptr3 = &k;
int* ptr4 = (int*) ptr3;
printf("*ptr3 = %d *ptr4 = %d\n", *ptr3, *ptr4);
return 0;
}
output is
*ptr3 = 10 *ptr4 = 1669824522
You have two undefined behaviour in one line.
When you dereference int * pointer you read outside the k object which is illegal.
Even if the k had enough size (for example is a char array), using the data as another type violates the strict aliasing rules - which is UB as well
Generally speaking, do not typecast pointers unless you really know what you are doing. If you want to convert byte array to integer use memcpy functionh.
A char is 1 byte in size, however, an integer is 4 bytes.
What you are doing is called Type Punning, where you are telling the compiler to not convert your char to an int and directly read 4 bytes from that same memory address while you are only allocating 1 byte. Those other 3 bytes could be anything.
The bytes of the char look like this:
10
Real simple, only one number. Integers need 3 more bytes than a char so here is what the integer could look like in bytes:
10 ? ? ?
The solution:
#include <stdio.h>
int main()
{
char k = 10;
int i = (int)k;
printf("k = %d i = %d\n", k, i);
return 0;
}
This code instead of directly reading the memory tells the compiler to convert the char to an int, filling in those 3 random bytes in the process with zeros. Here is what the variable i could look like in memory:
10 0 0 0
Those last 3 bytes were filled in with zeros and the integer is 10.
I hope this answer helps and I am open to feedback to improve it.
This question already has answers here:
printf() no format string printing character and integer arrays --> garbage
(3 answers)
Closed 2 years ago.
I am having a crazy output with funny characters (Φw ÅΩw) can i know what's wrong in the code?
probably the int main is wrong
i am obliged with int sumArray (int * a, int len , int * sum )format
#include <stdio.h>
#include <stdlib.h>
int sumArray(int *a, int len, int *sum) {
int sum1 = 0;
if (a == NULL || sum == NULL)
return -1;
int i;
(*sum) = 0;
for (i = 0; i < len; i++) {
(*sum) += a[i];
}
return 0;
}
int main() {
int *a = {1, 2, 3, 4};
int *b;
sumArray(&a, 4, &b);
printf(b);
return 0;
}
Can you try these changes ?
#include <stdio.h>
#include <stdlib.h>
int sumArray(int *a, int len, int *sum) {
// int sum1 = 0; // i removed this variable because you are not using it
if (a == NULL || sum == NULL)
return -1;
int i;
(*sum) = 0;
for (i = 0; i < len; i++) {
(*sum) += a[i];
}
return 0;
}
int main() {
// int *a = {1, 2, 3, 4};
int a[] = {1, 2, 3, 4};
int b;
// i rather declare an integer instead of a pointer to an integer
// when you declared int * b , this was a pointer, and your printf(b) was
// printing an address, not the value calculated by sumArray that is why you
// were printing funny characters
sumArray(a, 4, &b);
// a is already a pointer
printf("%d", b);
return 0;
}
You are using your pointers uninitialized. When you create a pointer, you don't know where the pointer points to. It either will be pointing to some garbage data, or in worse case, it will be pointing to a memory region which is already being used by some other program in your computer or maybe by OS itself.
If you really want to use pointers like this, you should dynamically allocate memory for them.
int* a = malloc( 4 * sizeof(int) );
int* b = malloc( sizeof(int) );
This makes sure that you can assign four integers to the memory region to which a points to. And one for b.
You then can wander in that memory using loops to assign, read or write data.
for ( int i=0; i < 4; i++ )
{
*(a + i) = i + 1;
}
Here we have a for loop which will run 4 times. Each time we are moving one block in the memory and putting the number we want there.
Remember, a is a pointer, it points to the beginning of a 4 int sized memory region. So in order to get to the next block, we are offsetting our scope with i. Each time the loop runs, a + i points to the "ith element of an array". We are dereferencing that region and assigning the value we want there.
for ( int i=0; i < 4; i++ )
{
printf("%d\n", *(a + i) );
}
And here we are using the same logic but to read data we just write.
Remember, you need to use format specifiers with printf function in order to make it work properly. printf() just reads the whatever data you happened to give it, and format specifier helps interpret that data in given format.
If you have a variable like int c = 65; when you use %d format specifier in the printf you will read the number 65. If you have %c specifier in the printf, you will read letter A, whose ASCII code happens to be 65. The data is the same, but you interpret it differently with format specifiers.
Now, your function int sumArray(int *a, int len, int *sum) accepts int pointer for the first argument. In the main function you do have an int pointer named a. But you are passing the address of a, which results in double indirection, you are passing the address of a pointer which holds address of an int array. This is not what you want, so & operator in the function call is excess. Same with b.
Call to the sumArray should look like
sumArray( a, 4, b );
And lastly, we should fix printf as well. Remember what I said about format specifiers.
And remember that b is not an int, it's int*, so if you want to get the value which b points to, you need to dereference it.
In the end, call to printf should look like
printf( "%d", *b );
Also, you should remember to free the memory that you dynamically allocated with malloc. When you use regular arrays or variables, your compiler deals with these stuff itself. But if you dynamically allocate memory, you must deallocate that memory using free whenever you are done with those pointers.
You can free a after the call to sumArray and b before terminating the main function like
free(a); and free(b);
In these kind of small projects freeing memory is probably won't cause any unwanted results, but this is a very very important subject about pointers and should be implemented properly in order to settle the better understanding of pointers and better programming practice.
In that form, your code should work as you intended.
BUT... And this is a big but
As you can see, to make such a simple task, we spent way more effort than optimal. Unless your goal is learning pointers, there is no reason to use pointers and dynamic allocation here. You could have used regular arrays as #Hayfa demonstrated above, and free yourself from a lot of trouble.
Using pointers and dynamic memory is a powerful tool, but it comes with dangers. You are playing with actual physical memory of your computer. Compilers nowadays won't let you to screw your OS while you are trying to add two numbers together but it still can result in hard to detect crashes especially in complex programs.
(Sorry if it's hard to read, I am not necessarily confident with text editor of Stack Overflow.)
#include <stdio.h>
typedef struct ss {
int a;
char b;
int c;
} ssa;
int main(){
ssa *ss;
int *c=&ss->a;
char *d=&ss->b;
int *e=&ss->c;
*c=1;
*d=2;
*e=3;
printf("%d=%p %d=%p %d=%p\n",*c,c++,*c,c++,*c,c);
return 0;
}
//prints 1=0x4aaa4333ac68 2=0x4aaa4333ac6c 3=0x4aaa4333ac70
My thinking of how should be the memory structure:
int | char | int
(68 69 6A 6B) (6C) (6D 6E 6F 70)
I'm trying to understand how this code works in memory.
Why int *e starts from 0x...70?
Why c++ (increment) from char (6C) goes 4 bytes more?
Thanks.
First of all, these lines are illegal:
*c=1;
*d=2;
*e=3;
All you have is a pointer to ssa, but you haven't actually allocated any space for the pointed-to object. Thus, these 3 lines are trying to write into unallocated memory, and you have undefined behavior.
Structure layout in memory is such that member fields are in increasing memory addresses, but the compiler is free to place any amount of padding in between for alignment reasons, although 2 structures sharing the same initial elements will have the corresponding members at the same offset. This is one reason that could justify the "gaps" between member addresses.
You should be more careful with how you call printf(). Argument evaluation order is undefined. You are changing the value of c more than once in between 2 sequence points (see Undefined behavior and sequence points). Furthermore, pointer arithmetic is only guaranteed to work correctly when performed with pointers that point to elements of the same array or one past the end.
So, in short: the code has undefined behavior all over the place. Anything can happen. A better approach would have been:
#include <stdio.h>
typedef struct ss {
int a;
char b;
int c;
} ssa;
int main() {
ssa ss = { 0, 0, 0 };
int *c = &ss.a;
char *d = &ss.b;
int *e = &ss.c;
printf("c=%p d=%p e=%p\n", (void *) c, (void *) d, (void *) e);
return 0;
}
The cast to void * is necessary. You will probably see a gap of 3 bytes between the value of d and e, but keep in mind that this is highly platform dependant.
There is often padding inside structures, you cannot assume that each field follows the one before it immediately.
The padding is added by the compiler to make structure member access quick, and sometimes in order to make it possible. Not all processors support unaligned accesses, and even those that do can have performance penalties for such accesses.
You can use offsetof() to figure out where there is padding, but typically you shouldn't care.
Even after casting a void pointer, I am getting compilation error while dereferencing it.
Could anyone please let me know the reason of this.
int lVNum = 2;
void *lVptr;
lVptr = (int*)&lVNum;
printf("\nlVptr[60 ] is %d \n",lVptr[1]);
It doesn't make sense to dereference a void pointer. How will the compiler interpret the memory that the pointer is pointing to? You need to cast the pointer to a proper type first:
int x = *(int*)lVptr;
printf("\nlVptr[60 ] is %d \n", *(int*)lVptr);
This will cast the void pointer to a pointer to an int and then dereference it correctly.
If you want to treat it as an array (of one), you could do a slightly ugly ((int *)lVptr)[0]. Using [1] is out of bounds, and therefore not a good idea (as for lVptr[60]...)
It's still a void* because that's what you declared it as. Any pointer may be implicitly converted to a void*, so that cast does nothing and you are left with a pointer to void just as you began with.
You'll need to declare it as an int*.
void *some_ptr = /* whatever */;
int *p = (int*)some_ptr;
// now you have a pointer to int cast from a pointer to void
Note that the cast to an int* is also unnecessary, for the same reason you don't have to (and should not) cast the return value of malloc in C.
void*'s can be implicitly converted to and from any other pointer type. I added the cast here only for clarity, in your code you would simply write;
int *p = some_void_ptr;
Also, this:
lVptr[1]
Is wrong. You have a pointer to a single int, not two. That dereference causes undefined behavior.
You can not dereference a void pointer because it doesn't have a type,
first you need to cast it(int *)lVptr, then dereference it *(int *)lVptr.
int lVNum = 2;
void *lVptr;
lVptr = &lVNum;
printf("\nlVptr[60 ] is %d \n",*(int *)lVptr);
Example of what you might be trying to do:
#include <stdio.h>
int main () {
void *v;
unsigned long int *i = (unsigned long int *)v;
*i = 5933016743776703571;
size_t j = sizeof(i);
printf("There are %ld bytes in v\n", j);
size_t k;
for (k = 0; k < j; k++) {
printf("Byte %ld of v: %c\n", k, ((char *)v)[k]);
}
}
Output:
There are 8 bytes in v
Byte 0 of v: S
Byte 1 of v: T
Byte 2 of v: A
Byte 3 of v: C
Byte 4 of v: K
Byte 5 of v: O
Byte 6 of v: V
Byte 7 of v: R
A void pointer is just that, a pointer to a void (nothing definable).
Useful in some instances.
For example malloc() returns a void pointer precisely because it allocated memory for an UNDEFINED purpose.
Some functions may likewise take void pointers as arguments because they don't care about the actual content other than a location.
To be honest, the snippet you posted makes absolutely no sense, can't even guess what you were trying to do.
# Code-Guru
I tried to compile it in visual studio. It gives error - expression must be a pointer to complete object.
Thanks teppic,
As you suggested, the following compiles and yields right result.
#include<stdio.h>
void main(){
printf("study void pointers \n");
int lvnum = 2;
void *lvptr;
lvptr = &lvnum;
printf("\n lvptr is %d\n",((int *)lvptr)[0]);
}
However if I try printf("\n lvptr is %d\n",((int *)lVptr)[60]);
It compiles and runs but gives random number.
Thanks a lot, friends for all the suggestions. Apologies that I assigned a void pointer to unnecessarily casted int pointer and expected it to get dereferenced. However I should have casted it when I want to dereference it.
Purpose of the snippet:
In my sources I found klocwork error which was caused by similar situation. On the contrary the program not only compiled but also gave correct results. Reason- it is a low level code (no OS) where the memory assigned to the void pointer is already reserved till the count of like 60. But the klocwork tool was unable to parse the files having that limit resulting in error. I did a lot of brain storming and ended up in something silly.
Saurabh
I am a linguist in charge of a C program, so please excuse me if the answer is obvious. I have the following code:
typedef struct array_s {
(...)
void **value;
} array_t;
typedef array_t *array_pt;
array_pt array_new (int size) {
(...)
array->value = (void **)malloc(size*sizeof(void *));
}
void* array_get (array_pt arr, int i) {
return arr->value[i];
}
int main () {
int a = 1234;
int *ptr = &a;
array_pt array = array_new(1);
array_add(array, ptr);
printf("%i\n", (int)array_get(array, 0));
}
It is supposed to provide me with a multi-purpose array (for storing int and char*, if I understood I can only use void), and I guess there are no problems of allocating/freeing. However, I cannot get to cast it into anything useful (i.e., get back the "original" int/char*), and for what I understood it could be because I am in a 64-bit system and the size of a pointer to void is different from the size of a pointer to int/char* (the program is supposed to be used in both 64 and 32 bit systems). I tried using intptr_t and other alternatives, to no luck.
How can I be sure that the code will accept any data type and work on both 32 and 64 bit systems? Thank you.
EDIT:
Sorry for not adding array_add, here it is:
unsigned int array_add (array_pt array, void *ptr) {
(...) // get the next index
// allocate if needed
array->value = (void **)realloc(array->value, array->size*sizeof(void *));
array->value[index] = p;
}
You need to dereference your pointer:
int* temp = array_get(array, 0);
printf("%i\n", *temp);
However, I strongly recommend avoiding this type of approach. You're basically giving away the small amount of help the compiler in C will normally provide - purposefully trying to make non-typesafe arrays.
You need to decide what is it you are trying to do in this case.
(1) If you want to use your void * array to store int values (actual int forcefully converted to void *), then you should add these int values to the array as follows
int a = 1234;
array_pt array = array_new(1);
array_add(array, (void *) a);
and then get them back from array as follows
int a = (int) array_get(array, 0);
printf ("%d\n", a);
or simply
printf ("%d\n", (int) array_get(array, 0)));
That last part is exactly what you did, but you got the first part wrong.
This is a cast-based approach, which is ugly in many ways, but it has certain practical value, and it will work assuming void * is large enough to hold an int. This is the approach that might depend on the properties of 32- and 64-bit systems.
(2) If you want to use your void * array to store int * values (pointers to int), then you should add these int values to the array as follows
int a = 1234;
array_pt array = array_new(1);
array_add(array, &a);
and then get them back from array as follows
int *pa = array_get(array, 0);
printf ("%d\n", *pa);
or simply
printf ("%d\n", *(int *) array_get(array, 0));
This approach is perfectly safe from any portability problems. It has no 32- or 64-bit issues. A void * pointer is guaranteed to safely hold a int * pointer or any other data pointer.
If that was your intent, then you got the first part right and the last part wrong.
Either this or that. You code appears to be a strange mix of the two, which is why it doesn't work, and which is why it is impossible to figure out from your original message which approach you were trying to use.
intmax_t should be an integer type that is 32 bits on 32bits compilers and 64bits on 64bit compilers. You could use %j in your printf statement to print intmax_t. The size of pointers on one system is always the same - independently of them pointing to int, char or void.
printf("%j\n", (intmax_t)array_get(array, 0));