Why the output is 4 and not 16 in this C code? - c

I dont understand why the output of this code is 4 and not 16, Assuming that unsigned int takes 4 bytes and long int takes 8 bytes. Any help?
#include <stdio.h>
struct test {
unsigned int x;
long int y : 33;
unsigned int z;
};
int main()
{
struct test t;
unsigned int* ptr1 = &t.x;
unsigned int* ptr2 = &t.z;
printf("%d", ptr2 - ptr1);
return 0;
}

I assume you expected the output to be 16, because the offset between the pointers should be 16 bytes (assuming sizes are as you mentioned in your question).
But in c when you subtract pointers, you don't get the number of bytes but the number of elements. The elements are the data the pointers point to.
Since these are unsigned int pointers, and assuming sizeof(unsigned int) is 4, the difference between thr pointers is 4 elements.
However - as #Lundin commented above this theoretical claculation is not really relevant because subtrating pointers that do not point the same array is UB (undefined behavior).
BTW - Note when you add an integral value to a pointer, a similar thing happens on the other way: the result is the address of the pointer plus the integral value times the size of the element pointed by the pointer. E.g.: if you add 1 to unsigned int* ptr1, the resulting address will be higher than ptr1 by 4.

Related

Type casting from char* to int*

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.

Why doesn't the modification of memory at *int_one alter the valueof memory at *int_two?

I wrote a pretty simple piece of C code:
int main(void) {
void *area = malloc(2 * sizeof(int));
unsigned int *int_one = (unsigned int *) area;
unsigned int *int_two = ((unsigned int *) area) + 3;
*int_two = 4293422034;
*int_one = 2;
printf("%u\n%u\n", *int_two, *int_one);
return 0;
}
sizeof(int) is 4 on my machine. Per my understanding, shouldn't the modification of memory at address int_one have an effect on the value stored at address int_two?
Modifying *int_one alters the first 4 bytes of mem. address area (perhaps not all 4, but enough to warrant the result I'm expecting?), and the integer at address int_two starts at the last byte of integer int_one.
So, shouldn't changing memory at int_one have an effect on memory at int_two?
Yet the printf call produces 4293422034 and 2 respectively.
I made sure to use unsigned variables to avoid confusion around 2s complement and negative values, and to use a small value for *int_one to warrant the change of its last byte (don't know if this is right?)
What am I not getting?
Operator '+', when applied to a pointer, increases the pointer n times the size of the object it points to. So increasing an int* by 3 does not add 3 bytes but 3*sizeof(int) bytes.
Pointer arithmetic is scaled by the size of the type the pointer points at. (sizeof(unsigned int) in your case). You'd need to cast to (char*) before adding 3 if you want to increase the address by 3 bytes, but converting that to an unsigned* pointer would incur undefined behavior by violating alignment requirements (6.3.2.3p7) and dereferencing the pointer would make the program even "more undefined" by violating strict aliasing rules (6.5p7).
To realy do this kind of type punning right, you'd need to use memcpy (or unions).
Example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
void *area = malloc(2 * sizeof(int));
if(!area) return EXIT_FAILURE;
unsigned int *int_one_p = area;
void *int_two_p = (((char*) area) + 3); /*saving this to an (unsigned*) would be UB*/
memcpy(int_two_p,&(unsigned){4293422034},sizeof(unsigned));
memcpy(int_one_p,&(unsigned){2},sizeof(unsigned));
unsigned one,two;
memcpy(&one,int_one_p, sizeof(one));
memcpy(&two,int_two_p, sizeof(two));
printf("%u\n%u\n", two, one);
return 0;
}

c casting pointer of type int* to char* and then accessing the value

Could somebody explain why the output value of this code is 64?
&a gets the address of a, it yields a pointer of type int*. This pointer of type int* is then cast to a pointer of type char*. Then you access the value at the address stored in ptr.
I know it is related to sizeof(char) == 1, but I just can't quite see how the output is 64.
#include<stdio.h>
int main(){
int a = 320;
char *ptr;
ptr =( char *)&a;
printf("%d ",*ptr);
return 0;
}
That's because a char has 8 bits (one byte) and an int can have 32 or 64 bits (4 or 8 bytes) depending on your system
I speak in terme of bits because the explanation here needs some understanding in how data is represented in your machine. This line :
int a = 320;
your int a here needs more than a byte to store its value since it's larger than 255 so it will store it in 2 bytes. 320 in binary is
00000001 01000000
^ ^
byte #2 | byte #1
so when you cast the int* to char* and access the first element pointed you get the first byte : 01000000 which equals 64. If you tried to access the second element of the char* you would find the value 1

Cast void pointer to integer array

I have a problem where I have a pointer to an area in memory. I would like to use this pointer to create an integer array.
Essentially this is what I have, a pointer to a memory address of size 100*300*2 = 60000 bytes
unsigned char *ptr = 0x00000000; // fictional point in memory goes up to 0x0000EA60
What i would like to achieve is to examine this memory as an integer array of size 100*150 = 15000 ints = 60000 bytes, like this:
unsigned int array[ 100 ][ 150 ];
I'm assuming it involves some casting though i'm not sure exactly how to formulate it. Any help would be appreciated.
You can cast the pointer to unsigned int (*)[150]. It can then be used as if it is a 2D array ("as if", since behavior of sizeof is different).
unsigned int (*array)[150] = (unsigned int (*)[150]) ptr;
Starting with your ptr declaration
unsigned char *ptr = 0x00000000; // fictional point in memory goes up to 0x0000EA60
You can cast ptr to a pointer to whatever type you're treating the block as, in this case array of array of unsigned int. We'll declare a new pointer:
unsigned int (*array_2d)[100][150] = (unsigned int (*)[100][150])ptr;
Then, access elements by dereferencing and then indexing just as you would for a normal 2d array.
(*array_2d)[50][73] = 27;
Some typedefs would help clean things up, too.
typedef unsigned int my_2d_array_t[100][150];
typedef my_2d_array_t *my_2d_array_ptr_t;
my_2d_array_ptr_t array_2d = (my_2d_array_ptr_t)ptr;
(*array_2d)[26][3] = 357;
...
And sizeof should work properly.
sizeof(array_2d); //4, given 32-bit pointer
sizeof(*array_2d); //60000, given 32-bit ints
sizeof((*array_2d)[0]); //600, size of array of 150 ints
sizeof((*array_2d)[0][1]); //4, size of 1 int

use of sizeof operator

The output of following program
#include<stdio.h>
int main(){
int *p[10];
printf("%ld %ld\n",sizeof(*p),sizeof(p));
}
is
8 <--- sizeof(*p) gives size of single element in the array of int *p[10]
80 <--- sizeof(p) gives size of whole array which is 10 * 8 in size.
now see the following program
#include<stdio.h>
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
int array[] = {23,34,12,17,204,99,16};
int main()
{
int d;
printf("sizeof(array) = %ld \n",sizeof(array));
printf("sizeof(array[0]) = %ld \n",sizeof(array[0]));
printf("sizeof int %ld\n",sizeof(int));
printf("TOTAL_ELEMENTS=%ld \n",TOTAL_ELEMENTS);
for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)
printf("%d\n",array[d+1]);
return 0;
}
is
sizeof(array) = 28
sizeof(array[0]) = 4 <--here
sizeof int 4
TOTAL_ELEMENTS=7
What I am not able to understand is why is the sizeof(array[0]) different in both the outputs.
int *p[10];
is an array of pointers.
*p
is the first element of that array of pointers. So it is a pointer to an integer. It is not an integer.
int array[] = {23,34,12,17,204,99,16}; is an array of integers. So array[0] is the first element of that array. So it is an integer.
The size of a pointer to an integer (*p) and an integer (array[0]) are different.
So sizeof(*p) and sizeof(array[0])
are different.
sizeof(p) gives the size of the array of pointers. So it is: 10 x 8 = 80.
i.e. (number of elements) x (size of one element)
sizeof(array) gives the size of the array of integers. So it is: 7 x 4 = 28.
In the first example, the element is a pointer to int, while in the second example it's just int. You can see that the pointer has 8 bytes, the int just 4 bytes.
In the first case, you've created an array of pointers to int, so their size is 8, not 4.
In the first example the size of a pointer is used and in the second the size of an integer. They may have different sizes especially on 64 bit systems.
array[0] has type int
*p has type int*
This perhaps demonstrates the stylistic folly of writing
int *p[10] ;
rather than
int* p[10] ;
where the second makes it clearer that int* is the type of the array being declared.
The 64-bit environment sets int to 32 bits and long and pointer to 64 bits ..
*p is a pointer - 8 bytes
sizeof(p) -is size of 10 pointers - so 80 bytes
Chances are you have AMD64 machine - check this for details (including other options)
http://gcc.gnu.org/onlinedocs/gcc/i386-and-x86_002d64-Options.html

Resources