Click here to Skip to main content
15,887,027 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello !

I've got a quick question, I was wondering what cast type changes. For example :

#include <stdio.h>
#include <stdlib.h>

int main()
{
int *x;
char *y;
float *z;

x = (int*)y;
y = (char*)z;

return 0;
}


I was wondering if something changes to be honest.
What do I mean ? The pointer arithmetics are based on the pointers them selfes and not by the value they have.

For example if pointer "x" is an int and it points to a char the arithmetic x+1 or x+i the sizeof is based on the type of the "x" and not the type of "y".

So why we need to change the cast of the other variables ?

Basically :

#include <stdio.h>
#include <stdlib.h>

int main()
{
int *x;
char *y;

x = (int*)y;
x = (char*)y;

return 0;
}


It shouldn't change anything.

I am aware that mixing types is not a good idea, but I was a bit mixed with the type casting to be honest.

PS.

I have found some examples how it looks like changing the type cast :
Quote:
*(int *)((char *)ptr + 2*sizeof(int))


Didn't really much know what happens here and why ptr type is changed twice. This is something about pointer arithmetics but I imagined it that if I have ptr + 1 then it is (ptr+1*sizeof(int)), and here I have (char*) and another (int*) so I have (ptr+1*sizeof(int)) times sizeof(char) and then times sizeof(int) ???? Weird.

What I have tried:

I tried to think mostly why it is like that when the pointer just takes the address so why changing the type.
Posted

Pointed type have different sizes so things become interesting when performing pointer arithmetic.
Moreover, the bit pattern interpretation of the pointed types are different so things become even more interesting when you try to deference the pointers.
If you know what are you doing, that could be useful. For instance, the following code
C
#include <stdio.h>
int main()
{
  float f = -0.25;
  printf("%04X", *(unsigned int *) &f);
}

outputs
BE800000

That is the bit pattern of the float, according with the IEEE 754 standard.
 
Share this answer
 
Comments
Member 16116753 18-Dec-23 10:45am    
But with an example with int *x and char *y. When I type x = (char*)y or x = (int*)y or x = (float *)y it doesn't change anything to be honest, because if I write x + 1 it will always shift by 4 bytes/8 bytes (depends on the system), no matter if it's x = (char*) y it will still shift by 4 bytes when x + 1, etc.

I don't really know how it works. I think that in this case no matter what "x" will see what type is there it won't change the arithmetics. The "x" is int type so the arithmetics are for intiger, so even if x = (char*) y, and I type x + 1 then the arithmetic will still shift by 4 bytes and not by 1 because it is by the type of pointer and not the pointer stuff so char doesn't matter to the arithmetics I think so ?

I am mostly new to C, so I don't really much know what I am doing so reading your code doesn't tell me a lot nor it tells me what happens in there ;D *&f like what ? and *(unsigned int *) &f. * is for getting value and & is to get the address so both at the same time hmmm ...
CPallini 18-Dec-23 10:55am    
In fact it does NOT change. For instance
int * x = (int *)y;
just means: "assign (the address of the value pointed by) y to x. The cast just make the compiler stop complaining about x and y being different pointer types.
Member 16116753 18-Dec-23 11:26am    
okey cool so no matter if it's int *x = (int *)y or int *x = (char *)y the arithmetics are still the same, which is for this example 4 bytes/8 bytes shift no matter what "y" will be. This is only for the compiler to stop complaining.
CPallini 19-Dec-23 7:34am    
Well, writing
int * x = (char *)y;

is senseless.
Member 16116753 19-Dec-23 7:53am    
I just wanted to emphasize that even if I write int* x = (char*) y; then if I write after that x + 1 it will still shift by 4 bytes and not by 1 byte so this char doesn't matter.
A cast does not make any changes to the data. It can be thought of as a signal to the compiler that "yes I know that x and y are different types, but do the assignment anyway!". The compiler then arranges for a bit-wise copy from x to y. If you do get a change in value, it will be because of the difference in size of the source and target eg
C
int i = 256;  /* 0x100 */
char c = i;  /*  c will be assigned 0x00 ie. last byte of i */

You do need to be careful when casting between pointers of different types. In general, a char pointer (a pointer to a single byte), has no alignment requirements, but other types, say an int, may require that it is aligned on a 4 byte boundary (or 2, 8 or 16, etc depending on the type). In that case, you might get a segfault when trying to dereference a pointer. e.g.
C
char str[5] = { 0x00, 0x00, 0x00, 0x00, 0x0 };  /* a 5 byte string, all zeros */
int *i = (int *)&(str[0]);
printf("*i = %d\n", *i);  
i = (int*)(&str[1]);
printf("*i = %d\n", *i);

Given the constraints above, one of the two printf statements will produce a seg fault, as one or the other of the int pointers are mis-aligned as per the CPU requirements. So you need to be careful what you do when casting pointers from one type to another. Note that malloc() and related calls are guaranteed to return a pointer that is correctly aligned for any type, so you have no problems doing type *ptr = (type*)malloc(sizeof(*ptr) * 42)
 
Share this answer
 
Comments
Member 16116753 18-Dec-23 11:25am    
I would like to ask because there are two different spelling with &(str[0]) and (&str[1]) dunno if it makes difference.

Second thing is why it would give segfault ? I didn't understand to be honest. str[1] from this point to str[4] it is 4 bytes.

Hmmm I also putted this code into compiler and it worked it printed both of them.
But maybe it shouldn't work ??? But it worked somehow.

What do I mean is that if the int was 8 bytes long then this 5 byte string isn't enough although it worked because of 0x0, I also wondered why.

I did another experiment :

#include <stdio.h>

int main()
{
    char str[5] = { 0x01, 0x00, 0x00, 0x00, 0x00 };  /* a 5 byte string, all zeros */
    int *i = (int *)&(str[0]);
    printf("*i = %d\n", *i);  
    i = (int*)(&str[1]);
    printf("*i = %d\n", *i);
    i = (int*)(&str[2]);
    printf("*i = %d\n", *i);
    i = (int*)(&str[3]);
    printf("*i = %d\n", *i);
}


And I had these results :

*i = 1
*i = 0
*i = 0
*i = -150994944


So it somehow worked for str[2] but it didn't works for str[3] because it took some random data in a non existing str[5] and str[6] I guess. It worked for str[2] even though there is non existing str[5] but repeating it always gave me 0, so maybe this spot always has 0, and in str[6] place there is random data so the 1 byte that is reserved for something random.

Interesting. Although I didn't understood the segfault
k5054 18-Dec-23 12:05pm    
As far as I can recall &(str[n]) and (&str[n]) are equivalent.

You didn't so much get a failure for the case of str[3], but invoked Undefined Behavior. Assuming an int is 4 bytes long, then an int starting at str[3] occupies str[3], str[4], str[5], str[6], and str[7]. You defined str to be only 5 bytes long, so the values of str[5] .. str[7] are unknown. If you have other variables on the stack, you might be looking into variables declared either before or after them. Or you might be looking at padding bytes, or data outside the current function's memory area, or you might even be bumping up against the boundary of a memory page, in which case you might get a segfault. I'm sure there are other things that might be going on. The C standard doesn't say what happens when you try to access elements beyond the end of an array.
Member 16116753 18-Dec-23 12:17pm    
Understandable, although I still have question for your code why is str[1] supposed to be segfault ? It is 4 byte for int str[1] ... str[4] in which str[4] is 0x0.
k5054 18-Dec-23 13:12pm    
For x86, x86-64, arm-32, and arm-64, it is not a requirement that an int be on a 4 byte boundary. But arm7 (eg. raspberry pi 32 bit OS), does have alignment requirements for floating point. So if you were try the same thing on a PI w. 32 bit os, but with float rather than int you will get a bus error when you try to access/modify an un-aligned floating point variable.
Member 16116753 18-Dec-23 13:16pm    
okey but in your example str[0] would work ok printing the value of variable "i" but str[1] not even though it has 4 required bytes, str[0] actually also has 4 bytes because I see you've assumed that int is 4 bytes so from str[0] to str[3] it works ok but when you've from str[1] to str[4] in which str[4] is equal 0x0 you've said it would be segfail. Why ?

"Given the constraints above, one of the two printf statements will produce a seg fault"

So str[4] is defined and this is the 4th byte for the int so why seg fault ?
If you do +1 on a pointer, it moves the pointer to the next address after the type.
If you do +1 on a pointer to 4 byte float, then the address will go up 4 bytes.
If you do +1 on a pointer to an 8 byte double, it will go up 8 bytes.

to understand why there are 2 casts, you have to look at the parentheses.
Casting to char is usually done because it makes any pointer arithmetic use '1' as size to count with.

So treating ptr as a char* and then adding 2 times the size of an int (which would be 4 in a 32 or 64 bit system by default). this means that you try to read an int, 8 bytes removed from ptr.
A much simpler way to write that would be

*((int *)ptr + 2)


Or if ptr is alread of int* type, simply do
*(ptr + 2)
 
Share this answer
 
v3
Comments
Member 16116753 18-Dec-23 10:30am    
It doesn't quite answer my question.

I gave an example with int *x and char *y. When I type x = (char*)y or x = (int*)y or x = (float *)y it doesn't change anything to be honest, because if I write x + 1 it will always shift by 4 bytes/8 bytes (depends on the system), no matter if it's x = (char*) y it will still shift by 4 bytes when x + 1, etc.

Why adding cast types matters though in this situation.

Second thing, as I understood if I write *((char*)ptr + 2) then the arithmetics changes and instead of 2*sizeof(int) changes into 2*sizeof(char) ??
Bruno van Dooren 18-Dec-23 10:55am    
>> if I write *((char*)ptr + 2) then the arithmetics changes and instead of 2*sizeof(int) changes into 2*sizeof(char) ??

that is correct.

>> if it's x = (char*) y it will still shift by 4 bytes when x + 1, etc

No, it won't. if X is of type char* and you do +1 it will shift by 1 byte.
Member 16116753 18-Dec-23 11:11am    
The "x" is type of int

int *x;
char *y;

x = (char *)y;

typic x + 1, the arithmetics is that it adds 4 bytes (for 32 bit) and not 1 byte. Because "x" is int and not char i just changed y to be a char.
Bruno van Dooren 18-Dec-23 12:15pm    
YOU say: if it's x = (char*) y it will still shift by 4 bytes when x + 1, etc

x is a char*.
If you declare x as int* you are ignoring compiler warnings.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900