This may be a noob question ..but this is really confusing me..
Below is some sample code
void main() {
int a = 300;
char *ptr = &a;
int *intptr = &a;
printf("%d\n %d\n", *ptr, *intptr);
}
output:
44
300
As per my understanding,why dereferencing *ptr prints 44 is due to the fact that char pointer is one byte and so it reads only 8 bits from the address of int...
But this question:What is the size of a pointer? states Regardless of what data type they are pointing to, they have fixed size
Am i missing some thing.Why dereferencing char pointer prints 44,if pointer size is same ?
Object pointers (e.g. pointers to anything besides a function) are typically the same size on most systems you're likely to come across, however there's no guarantee of that. That being said, even though the pointers may be the same size, the types that they point to are not.
For example, on a 64-bit Windows system, pointers are typically 8 bytes in size. In your example you have char * and an int * which are most likely both 8 bytes. The difference here is that dereferencing a char * will read/write 1 byte while dereferenceing an int * will read/write 4 bytes (assuming an int is 32 bit).
Assuming little endian byte ordering, a looks like this in memory:
------------------
a | 44 | 1 | 0 | 0 |
------------------
Both ptr and intptr contain the address of a. When dereferencing ptr, which is of type char *, it only looks at the first byte. In contrast, when dereferencing intptr, which is of type int *, it looks at all 4 bytes.
First of all, your code is not valid C and it also invokes undefined behavior, so anything can happen. If your compiler didn't show you any diagnostic messages, you need to uninstall it and get a working one instead. You have the following bugs:
void main() will only work on freestanding implementations that specifically allow this form of main.
char *ptr = &a; is not a valid form of assignment in C. The pointers are not compatible(1).
Printing a character with the %d format specifier invokes undefined behavior.
After fixing these bugs, we get:
#include <stdio.h>
int main (void)
{
int a = 300;
char *ptr = (char*)&a;
int *intptr = &a;
printf("%d\n %d\n", (int)*ptr, *intptr);
}
None of this prints the size of a pointer. You print the contents of the first byte in the int a, which you translate to a char, which may or may not be signed and possibly give an incorrect result (this part is endianess-dependent). And then you print the contents of the whole int a.
What you seem to want is to print the size of the pointers themselves:
printf("%zu %zu\n", sizeof ptr, sizeof intptr);
(1) C11 6.5.16.1 emphasis mine:
Constraints
One of the following shall hold:
/--/
- 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;
In this statement
printf("%d\n %d\n", *ptr, *intptr);
there are outputted not the pointers themselves but the data they point to.
For example 300 can be represented like 256 + 44. So 44 can be stored in one byte while 256 can be stored in another byte. And this expression *ptr gives the value 44 stored in the byte pointed to by the pointer ptr.
On the other hand the pointer intptr points to the whole object of the type int and the expression *intptr gives the value 300.
If you want to output the addresses stored in the pointers you should write
printf("%p\n %p\n", ( void * )ptr, ( void * )intptr);
To output sizes of the pointers you could write
printf("%zu\n %zu\n", sizeof( ptr ), sizeof( intptr ));
Take into account that according to the C Standard the function main without parameters shall be declared like
int main( void )
Also in this declaration you should use an explicit casting
char *ptr = ( char * )&a;
Here is a demonstrative program
#include <stdio.h>
int main(void)
{
int a = 300;
char *ptr = ( char * )&a;
int *intptr = &a;
printf( "*ptr = %d, *intptr = %d\n", *ptr, *intptr );
printf( "ptr = %p, intptr = %p\n", ( void * )ptr, ( void * )intptr );
printf( "sizeof( ptr ) = %zu, sizeof( intptr ) = %zu\n",
sizeof( ptr ), sizeof( intptr ) );
return 0;
}
Its output might look like
*ptr = 44, *intptr = 300
ptr = 0x7ffe5972613c, intptr = 0x7ffe5972613c
sizeof( ptr ) = 8, sizeof( intptr ) = 8
You introduce undefined behaviour if you cast a pointer to an object to a different type than that of the object AND access it then through this pointer.
Statement int a = 300 introduces an object of type int, char* ptr = &a introduces a pointer to an object of type char but let it point to an object of type int. This per se is not a problem, but dereferencing this pointer then through *ptr is undefined behaviour. And this does not have something to do with the printf - a statement like char x = *ptr would be UB, too. However, a statement like int x = *((int *)ptr) would be OK, as the ptr is casted back to the original type of the object it points to.
Concerning the sizes of pointers: The size of a pointer (i.e. the value necessary for storing a memory address to which the pointer points to) is fixed size; it's usually 4 bytes on a 32 bit system and 8 bytes on a 64 bit system. The size necessary for representing a memory address has nothing to do with the size of the object that resides at the respecite memory address to which the pointer points to.
The following example demonstrates this behaviour:
int main() {
int a = 300;
void *ptr = &a;
int *intptr = &a;
printf("%d %d\n", *((int*)ptr), *intptr);
}
Output:
300 300
Indeed, on a little endian architecture, the LSB would appear first in memory, thus to store 300, memory looks like
44 , 1 , 0 , 0 (for a size 4 int)
The
printf("%d\n %d\n", *ptr, *intptr);
doesn't print the pointer sizes (which are likely the same), it prints the dereferenced pointers, values of one byte, a char, then the int value.
To print the pointer sizes
printf ("%zu\n%zu\n", sizeof(ptr), sizeof(intptr));
Code
#include <stdio.h>
#include <stdint.h>
unsigned int
trans(unsigned char c){
if ('0' <=c && c <= '9') return c - '0';
if ('A' <=c && c <= 'F') return c - 'A' + 0x0A;
if ('a' <=c && c <= 'f') return c - 'a' + 0x0A;
return 0;
}
uint16_t
hex_to_uint16(const char* s) {
char *p = (char*) s;
uint16_t v = 0;
while (*p) {
if (p > s) v = v << 4;
v += trans(*p);
p++;
}
return v;
}
int main (void)
{
int n = 1;
// little endian if true
if(*(char *)&n == 1) {printf("little\n");}
int a = 300;
char *ptr = (char*)&a;
int *intptr = &a;
printf("charSize:%zu intSize:%zu\n", sizeof (char), sizeof (int));
printf("PcharSize:%zu PintSize:%zu\n", sizeof (ptr), sizeof (intptr));
//printf("Hex: %x, Decimal: %d\n", 0x2c, (int)0x2c );
//printf("int: %d\n", hex_to_uint16("2c"));
//printf("300H: %x\n", (a));
printf("PcharAddr: %p\nPintAddr: %p\n", ptr, intptr);
printf("int: %d\n", *intptr);
printf("LSB | | | MSB|\n");
printf(" 0 | 1 | 2 | 3 |\n");
printf("------------------------\n");
printf("Dec\n");
printf(" %d %d %d %d\n", *(ptr), *(ptr+1), *(ptr+2), *(ptr+3));
printf("Hex\n");
printf(" %x %x %x %x\n", *(ptr), *(ptr+1), *(ptr+2), *(ptr+3));
printf("To Big Endian:\n%.2x%x%x%x\n", (uint8_t)*(ptr+3), (uint8_t)*(ptr+2), (uint8_t)*(ptr+1), (uint8_t)*(ptr));
///https://stackoverflow.com/questions/19275955/convert-little-endian-to-big-endian
/*
* chux aswer
uint32_t num = 300;
uint8_t b[4];
b[0] = (uint8_t) (num >> 0u);
b[1] = (uint8_t) (num >> 8u);
b[2] = (uint8_t) (num >> 16u);
b[3] = (uint8_t) (num >> 24u);
printf("%x%x%x%x\n", b[3], b[2], b[1], b[0]);
*/
return 0;
}
Compile, Run
gcc -Wall -Wextra te.c -o te && ./te
no, no, no
As per my understanding,why dereferencing *ptr prints 44 is due to the fact that char pointer is one byte and so it reads only 8 bits from the address of int...
char is one byte, not char pointer. If you want to print pointer you should
printf("%p\n %p\n", ptr, intptr);
Related
void main() {
char var = 10;
char *ptr = &var;
printf("Pointer address before increment:%p\n", ptr);
printf("sizeof(ptr):%d\n", sizeof(ptr));
ptr++;
printf("Pointer address after increment:%p\n", ptr);
printf("sizeof(ptr):%d\n", sizeof(ptr));
}
Output:
Pointer address before increment:0x7fffb997144f
sizeof(ptr):8
Pointer address after increment:0x7fffb9971450
sizeof(ptr):8
Why does the char pointer increment by one byte only? Its size is 8, right?
When ptr is declared, the compiler allocates 8 bytes to it. When we increment it by 1, it increments based on the datatype. Why? How does this works?
For starters to output values of the type size_t you need to use the conversion specifier zu instead of d
printf("sizeof(ptr):%zu\n",sizeof(ptr));
^^^
Incremented pointer points to the memory after the object it points to. That is the value of a pointer of the type T * is incremented by the value sizeof( T ).
Consider for example accessing array elements.
T a[N];
The expression a[i] evaluates like +( a + i ). So the value of the pointer is incremented by i * sizeof( T ).
This is called the pointer arithmetic,
As for the size of objects of the type char then according to the C Standard sizeof( char ) is always equal to 1.
Also consider the following demonstration program.
#include <stdio.h>
int main( void )
{
char s[] = "Hello";
for ( const char *p = s; *p != '\0'; ++p )
{
putchar( *p );
}
putchar( '\n' );
}
Its output is
Hello
If the pointer p was incremented by the value sizeof( char * ) then you could not output the array using the pointer.
For pointer arithmetics, what matters is not the sizeof the pointer, but the size of the type it points to:
T a[10]; T *p = a; defines a pointer p to an array of objects of type T.
p contains the memory address of the first element of a.
The next element's address is sizeof(T) bytes farther, so incrementing the pointer p by 1 increments the memory address by sizeof(*p).
Here is a modified version:
#include <stdio.h>
int main() {
char char_array[2] = "a";
char *char_ptr = char_array;
printf("sizeof(char_ptr): %zu\n", sizeof(char_ptr));
printf("char_ptr before increment: %p\n", (void *)char_ptr);
printf("sizeof(*char_ptr): %zu\n", sizeof(*char_ptr));
char_ptr++;
printf("char_ptr after increment: %p\n", (void *)char_ptr);
int int_array[2] = { 1, 2 };
int *int_ptr = int_array;
printf("\nsizeof(int_ptr): %zu\n", sizeof(int_ptr));
printf("int_ptr before increment: %p\n", (void *)int_ptr);
printf("sizeof(*int_ptr): %zu\n", sizeof(*int_ptr));
int_ptr++;
printf("int_ptr after increment: %p\n", (void *)int_ptr);
return 0;
}
Output (64 bits):
sizeof(char_ptr): 8
char_ptr before increment: 0x7fff52c1f7ce
sizeof(*char_ptr): 1
char_ptr after increment: 0x7fff52c1f7cf
sizeof(int_ptr): 8
int_ptr before increment: 0x7fff52c1f7c0
sizeof(*int_ptr): 4
int_ptr after increment: 0x7fff52c1f7c4
Output (32 bits):
sizeof(char_ptr): 4
char_ptr before increment: 0xbffc492e
sizeof(*char_ptr): 1
char_ptr after increment: 0xbffc492f
sizeof(int_ptr): 4
int_ptr before increment: 0xbffc4930
sizeof(*int_ptr): 4
int_ptr after increment: 0xbffc4934
That's because a charactor occupies 1 byte, while a pointer to charactor is a pointer, not a charactor or something else, that means it stored a memory adress, so it occupies 8 bytes. Also all kinds of pointer is 8 bytes on your machine.
What are pointers?
Briefly the pointers are a special types of variables for holding memory addresses and its bit wide or byte size that the compilers allocate may vary depending on the platform. If you size a pointer using the sizeof operator in an 8-bit architecture for example, in most devices you will get 2 bytes, that is, a pointer can hold an address value up to 64kB. This is logically big enough to hold address value for devices that only has up to 64kB of ROM and up to a few kBs of RAM.
Since the architecture in which you compile your code is a 64-bit architecture, the system registers are 64-bits wide and it's wide enough to hold very large address values (2 * 10^64). Since its big enough it will naturally size 64-bits / 8 bytes.
As said the pointers are special objects, so you cannot assign kinds of constants like
int* ptr = 0x7fffb997144f; // Compilers will not allow this
Compilers will not allow this because the pointers are not regular kind of variables. So in order to assign a constant address value you must cast it as pointer like in the following example:
int* ptr = (int*) 0x7fffb997144f; // Compilers will allow this
How the pointers are incremented
It depends on the byte size of the type to which a pointer points. That is;
1 for char types
2 for short int types
4 for long types
8 for long long types
Some type sizes like of int and float types may vary depending on the platform.
Now that we know about pointers and how it is incremented let's make an example for each type above. Let's assume that the start address for each example is 0x7fffb997144f.
For char types
char vars[5];
char* ptr = vars; // 0x7fffb997144f
ptr++; // 0x7fffb9971450
ptr++; // 0x7fffb9971451
For short int types
short int vars[5];
short int* ptr = vars; // 0x7fffb997144f
ptr++; // 0x7fffb9971451
ptr++; // 0x7fffb9971453
For long types
long vars[5];
long* ptr = vars; // 0x7fffb997144f
ptr++; // 0x7fffb9971454
ptr++; // 0x7fffb9971458
For long long types
long long vars[5];
long long* ptr = vars; // 0x7fffb997144f
ptr++; // 0x7fffb9971458
ptr++; // 0x7fffb997145f
I don't understand why I can't print out ints b and c in this way:
#include "stdio.h"
typedef struct{
int a;
int b;
int c;
} myStruct;
int main(){
myStruct MS;
MS.a = 13;
MS.b = 27;
MS.c = 39;
myStruct* pMS = &MS;
printf("pMS = %u\n", pMS );
printf("&a = %u\n", &pMS->a ); // addr of a is addr of struct
printf("&b = %u\n", &pMS->b ); // addr of b is +4 from a
printf("&c = %u\n", &pMS->c ); // addr of c is +8 from a
printf("*pMS = %d\n",*(pMS) );
printf("*pMS+4 = %d\n",*(pMS+4) );
printf("*pMS+8 = %d\n",*(pMS+8) );
}
The terminal shows bogus values for b and c (at least, I think b and c should be located at pMS+4 and pMS+8):
gcc version 4.6.3
pMS = 1926301980
&a = 1926301980
&b = 1926301984
&c = 1926301988
*pMS = 13
*pMS+4 = 32765
*pMS+8 = 32765
pMS+4 is not the address of the integer located four bytes beyond the start of the structure. Additions to pointers are scaled based on the pointer type so, if it were a pointer to an integer, it would be four integers beyond the start (16 bytes if you have 32-bit ints). See, for example:
int someInt[2] = {4, 9}; // assume 4-byte int, big-endian
int *x = &someInt[0];
// | someInt[0] # 0x1000 | someInt[1] # 0x1004 |
// | 0,0,0,4 | 0,0,0,9 |
// | x = 0x1000 | x+1 = 0x1004 |
// | *(x) = 4 | *(x+1) = 9 |
However, it's even worse in your case since your pointer is to the actual structure. That means it's scaling by the size of the entire struct, three complete integers (plus padding if needed).
This line for example
printf("*pMS+4 = %d\n",*(pMS+4) );
When you add to the pointer, it is same as indexing to array, so equal to this:
printf("*pMS+4 = %d\n", pMS[4]);
Of course there is no array, so bogus struct value is passed.
And then printf can't print structs at all, %d prints something non-sensical.
Double undefined behavior, in other words.
By perform some changes on code and implementing what #Jonathan Leffler saying on comments this way works for me.
Code
#include <stdio.h>
struct t{
int a;
int b;
int c;
};
int main(){
struct t MS;
MS.a = 13;
MS.b = 27;
MS.c = 39;
struct t* pMS = &MS;
printf("pMS =%p\n", pMS );
printf("&a = %p\n", &pMS->a ); // addr of a is addr of struct
printf("&b = %p\n", &pMS->b ); // addr of b is +4 from a
printf("&c = %p\n", &pMS->c ); // addr of c is +8 from a
printf("*pMS.a = %d\n", (* ((int *) ((void *) pMS))));//13
printf("*pMS.b = %d\n", (* ((int *) ((void *) pMS)+1)));//27
printf("*pMS.c = %d\n", (* ((int *) ((void *) pMS)+2)));//39
return 0;
}
But also this works, as you see in #hyde answer working with this way not good. structures in C are packed depending on CPU architecture, Compiler means putting struct members in packed form, for example below struct takes 8 Bytes instead of 5.
struct example {
int a;
char b;
};
I use my way because i checked before, sizeof(void *), sizeof(int *) both return 4.
Consider these lines:
printf("*pMS.a = %d\n", (* ((int *) ((void *) pMS))));//13
printf("*pMS.b = %d\n", (* ((int *) ((void *) pMS)+1)));//27
printf("*pMS.c = %d\n", (* ((int *) ((void *) pMS)+2)));//39
Why using +1 inside parenthesis cause accessing to our integers?
On my system integers numbers occupy 4 bytes, as i expressed above void * and int * have size of same 4 Bytes.
First remove void * to simplify (int *) (pMS) + 1, behave pMS like an integer size, when we add one to it jumps to next for byte address that refers to 27.
I think adding void * is for remove UB from code, as pointer have void * type pointer to structure.
For this case removing void * also works.
At last
printf("pMS =%u\n", sizeof(MS) );//12(3 * 4)
printf("pMS =%u\n", sizeof(pMS) );//4
In my platform there is no any padding or packing, as see above entire structure hold 12 byte 3 integers with 4 bytes size.
But pMs that is a pointer to first address of this structure, as first elements is integer this have 4 byte size.
ToDO
Edit post to add some further explain about pointers type and arithmetic.
Some extra things on difference between two way of using structure in this case.
Structure padding, packing depending on platform, OS, Compiler.
Why we see different address of structure when declare Global or Local inside main, that case different behavior in this case?
#include<stdio.h>
int main()
{
char arr[] = "somestring";
char *ptr1 = arr;
char *ptr2 = ptr1 + 3;
printf("ptr2 - ptr1 = %ld\n", ptr2 - ptr1);
printf("(int*)ptr2 - (int*) ptr1 = %ld", (int*)ptr2 - (int*)ptr1);
return 0;
}
I understand
ptr2 - ptr1
gives 3 but cannot figure out why second printf prints 0.
It's because when you substract two pointers, you get the distance between the pointer in number of elements, not in bytes.
(char*)ptr2-(char*)ptr1 // distance is 3*sizeof(char), ie 3
(int*)ptr2-(int*)ptr1 // distance is 0.75*sizeof(int), rounded to 0
EDIT: I was wrong by saying that the cast forces the pointer to be aligned
If you want to check the distance between addresses don't use (int *) or (void *), ptrdiff_t is a type able to represent the result of any valid pointer subtraction operation.
#include <stdio.h>
#include <stddef.h>
int main(void)
{
char arr[] = "somestring";
char *ptr1 = arr;
char *ptr2 = ptr1 + 3;
ptrdiff_t diff = ptr2 - ptr1;
printf ("ptr2 - ptr1 = %td\n", diff);
return 0;
}
EDIT: As pointed out by #chux, use "%td" character for ptrdiff_t.
Casting a char pointer with int* would make it aligned to the 4bytes (considering int is 4 bytes here). Though ptr1 and ptr2 are 3 bytes away, casting them to int*, results in the same address -- hence the result.
This is because sizeof(int) == 4
Each char takes 1 byte. Your array of chars looks like this in memory:
[s][o][m][e][s][t][r][i][n][g][0]
When you have an array of ints, each int occupies four bytes. storing '1' and '2' conceptually looks more like this:
[0][0][0][1][0][0][0][2]
Ints must therefore be aligned to 4-byte boundaries. Your compiler is aliasing the address to the lowest integer boundary. You'll note that if you use 4 instead of 3 this works as you expected.
The reason you have to perform a subtraction to get it to do it (just passing the casted pointers to printf doesn't do it) is because printf is not strictly typed, i.e. the %ld format does not contain the information that the parameter is an int pointer.
Can anyone explain the logic how to add a and b?
#include <stdio.h>
int main()
{
int a=30000, b=20, sum;
char *p;
p = (char *) a;
sum = (int)&p[b]; //adding a and b!
printf("%d",sum);
return 0;
}
The + is hidden here:
&p[b]
this expression is equivalent to
(p + b)
So we actually have:
(int) &p[b] == (int) ((char *) a)[b]) == (int) ((char *) a + b) == a + b
Note that this technically invokes undefined behavior as (char *) a has to point to an object and pointer arithmetic outside an object or one past the object invokes undefined behavior.
C standard says that E1[E2] is equivalent to *((E1) + (E2)). Therefore:
&p[b] = &*((p) + (b)) = ((p) + (b)) = ((a) + (b)) = a + b
p[b] is the b-th element of the array p. It's like writing *(p + b).
Now, when adding & it'll be like writing: p + b * sizeof(char) which is p + b.
Now, you'll have (int)((char *) a + b) which is.. a + b.
But.. when you still have + in your keyboard, use it.
As #gerijeshchauhan clarified in the comments, * and & are inverse operations, they cancel each other. So &*(p + b) is p + b.
p is made a pointer to char
a is converted to a pointer to char, thus making p point to memory with address a
Then the subscript operator is used to get to an object at an offset of b beyond the address pointed to by p. b is 20 and p+20=30020 . Then the address-of operator is used on the resulting object to convert the address back to int, and you've got the effect of a+b
The below comments might be easier to follow:
#include <stdio.h>
int main()
{
int a=30000, b=20, sum;
char *p; //1. p is a pointer to char
p = (char *) a; //2. a is converted to a pointer to char and p points to memory with address a (30000)
sum = (int)&p[b]; //3. p[b] is the b-th (20-th) element from address of p. So the address of the result of that is equivalent to a+b
printf("%d",sum);
return 0;
}
Reference: here
char *p;
p is a pointer (to element with size 1 byte)
p=(char *)a;
now p points to memory with address a
sum= (int)&p[b];
p pointer can be use as array p[] (start address (in memory) of this array is a)
p[b] means to get b-th element - this element address is a+b
[ (start address)a + b (b-th element * size of element (1 byte)) ]
&p[b] means to get address of element at p[b] but its address is a+b
if you use pointer to int (mostly 4 bytes)
int* p
p = (int*)a;
your sum will be a+(4*b)
int a=30000, b=20, sum;
char *p; //1. p is a pointer to char
p = (char *) a;
a is of type int, and has the value 30000. The above assignment converts the value 30000 from int to char* and stores the result in p.
The semantics of converting integers to pointers are (partially) defined by the C standard. Quoting the N1570 draft, section 6.3.2.3 paragraph 5:
An integer may be converted to any pointer type. Except as previously
specified, the result is implementation-defined, might not be
correctly aligned, might not point to an entity of the referenced
type, and might be a trap representation.
with a (non-normative) footnote:
The mapping functions for converting a pointer to an integer or an
integer to a pointer are intended to be consistent with the addressing
structure of the execution environment.
The standard makes no guarantees about the relative sizes of types int and char*; either could be bigger than the other, and the conversion could lose information. The result of this particular conversions is very unlikely to be a valid pointer value. If it's a trap representation, then the behavior of the assignment is undefined.
On a typical system you're likely to be using, char* is at least as big as int, and integer-to-pointer conversions probably just reinterpret the bits making up the integer's representation as the representation of a pointer value.
sum = (int)&p[b];
p[b] is by definition equivalent to *(p+b), where the + denotes pointer arithmetic. Since the pointer points to char, and a char is by definition 1 byte, the addition advances the pointed-to address by b bytes in memory (in this case 20).
But p is probably not a valid pointer, so any attempt to perform arithmetic on it, or even to access its value, has undefined behavior.
In practice, most C compilers generate code that doesn't perform extra checks. The emphasis is on fast execution of correct code, not on detection of incorrect code. So if the previous assignment to p set it to an address corresponding to the number 30000, then adding b, or 20, to that address will probably yield an address corresponding to the number 30020.
That address is the result of (p+b); now the [] operator implicitly applies the * operator to that address, giving you the object that that address points to -- conceptually, this is a char object stored at an address corresponding to the integer 30020.
We immediately apply the & operator to that object. There's a special-case rule that says applying & to the result of a [] operator is equivalent to just doing the pointer addition; see 6.5.3.2p2 in the above referenced standard draft.
So this:
&p[b]
is equivalent to:
p + b
which, as I said above, yields an address (of type char*) corresponding to the integer value 30020 -- assuming, of course, that integer-to-pointer conversions behave in a certain way and that the undefined behavior of constructing and accessing an invalid pointer value don't do anything surprising.
Finally, we use a cast operator to convert this address to type int. Conversion of a pointer value to an integer is also implementation-defined, and possibly undefined. Quoting 6.3.2.3p6:
Any pointer type may be converted to an integer type. Except as
previously specified, the result is implementation-defined. If the
result cannot be represented in the integer type, the behavior is
undefined. The result need not be in the range of values of any
integer type.
It's not uncommon for a char* to be bigger than an int (for example, I'm typing this on a system with 32-bit int and 64-bit char*). But we're relatively safe from overflow in this case, because the char* value is the result of converting an in-range int value. there's no guarantee that converting a given value from int to char* and back to int will yield the original result, but it commonly works that way, at least for values that are in range.
So if a number of implementation-specific assumptions happen to be satisfied by the implementation on which the code happens to be running, then this code is likely to yield the same result as 30000 + 20.
Incidentally, I've worked on a system where this would have failed. The Cray T90 was a word-addressed machine, with hardware addresses pointing to 64-bit words; there was no hardware support for byte addressing. But char was 8 bits, so char* and void* pointers had to be constructed and manipulated in hardware. A char* pointer consisted of a 64-bit word pointer with a byte offset stored in the otherwise unused high-order 3 bits. Conversions between pointers and integers did not treat these high-order bits specially; they were simply copied. So ptr + 1 and (char*)(int)ptr + 1) could yield very different results.
But hey, you've managed to add two small integers without using the + operator, so there's that.
An alternative to the pointer arithmetic is to use bitops:
#include <stdio.h>
#include <string.h>
unsigned addtwo(unsigned one, unsigned two);
unsigned addtwo(unsigned one, unsigned two)
{
unsigned carry;
for( ;two; two = carry << 1) {
carry = one & two;
one ^= two;
}
return one;
}
int main(int argc, char **argv)
{
unsigned one, two, result;
if ( sscanf(argv[1], "%u", &one ) < 1) return 0;
if ( sscanf(argv[2], "%u", &two ) < 1) return 0;
result = addtwo(one, two);
fprintf(stdout, "One:=%u Two=%u Result=%u\n", one, two, result );
return 0;
}
On a completely different note, perhaps what was being looked for was an understanding of how binary addition is done in hardware, with XOR, AND, and bit shifting. In other words, an algorithm something like this:
int add(int a, int b)
{ int partial_sum = a ^ b;
int carries = a & b;
if (carries)
return add(partial_sum, carries << 1);
else
return partial_sum;
}
Or an iterative equivalent (although, gcc, at least, recognizes the leaf function and optimizes the recursion into an iterative version anyway; probably other compilers would as well)....
Probably needs a little more study for the negative cases, but this at least works for positive numbers.
/*
by sch.
001010101 = 85
001000111 = 71
---------
010011100 = 156
*/
#include <stdio.h>
#define SET_N_BIT(i,sum) ((1 << (i)) | (sum))
int sum(int a, int b)
{
int t = 0;
int i = 0;
int ia = 0, ib = 0;
int sum = 0;
int mask = 0;
for(i = 0; i < sizeof(int) * 8; i++)
{
mask = 1 << i;
ia = a & mask;
ib = b & mask;
if(ia & ib)
if(t)
{
sum = SET_N_BIT(i,sum);
t = 1;
/*i(1) t=1*/
}
else
{
t = 1;
/*i(0) t=1*/
}
else if (ia | ib)
if(t)
{
t = 1;
/*i(0) t=1*/
}
else
{
sum = SET_N_BIT(i,sum);
t = 0;
/*i(1) t=0*/
}
else
if(t)
{
sum = SET_N_BIT(i,sum);
t = 0;
/*i(1) t=0*/
}
else
{
t = 0;
/*i(0) t=0*/
}
}
return sum;
}
int main()
{
int a = 85;
int b = 71;
int i = 0;
while(1)
{
scanf("%d %d", &a, &b);
printf("%d: %d + %d = %d\n", ++i, a, b, sum(a, b));
}
return 0;
}
The Code used
#include<stdio.h>
struct st
{
char a;
short c;
int b;
};
struct st s1;
int main()
{
printf("%p %p \n",(&s1.b)-1, &s1);
}
If I print the address of &s1.b it prints 0x804a01c and &s1.b-2 prints 0x804a018
why it is printing same address 0x804a01c if i select &s1.b-1 ?
There's probably something wrong with your printing code.
#include <stdio.h>
struct st
{
char a;
short c;
int b;
};
struct st s1;
int main() {
printf("%p\n", (void*)(&s1.b));
printf("%p\n", (void*)(&s1.b - 1));
printf("%p\n", (void*)(&s1.b - 2));
}
Output:
0x403024
0x403020
0x40301c
Most likely you're printing it wrong:
#include <stdio.h>
struct st
{
char a;
short c;
int b;
};
struct st s;
int main(void)
{
printf("s: %p\n", (void *)&s);
printf("s.a: %p\n", (void *)&s.a);
printf("s.b: %p\n", (void *)&s.b);
printf("s.b-1: %p\n", (void *)(&s.b-1));
printf("s.b-2: %p\n", (void *)(&s.b-2));
return 0;
}
Prints for me:
s: 0x100001068
s.a: 0x100001068
s.b: 0x10000106c
s.b-1: 0x100001068
s.b-2: 0x100001064
Things to note:
Pointer to struct == pointer to struct's first element (guaranteed by the C standard),
I am printing the pointers with "%p" format string. "%p" needs void *, and since printf is a variadic function, I need to cast the arguments to printf to void * in this case.
What does the above program print for you?
Edit: based upon the actual code posted for printing that you posted later: you are not getting the same value for &s1.b and &s1.b-1. You are getting the same value for &s1.b-1 and &s1. The answer to that is: this happens because of chance. In your case, there is struct padding, and sizeof(short)+sizeof(char) happens to be ≤ sizeof(int). If you were on a machine where any of those assumptions were invalid, you wouldn't see that behavior. I am sure if you changed char or short to int in your code, &s1.b-1 would not equal &s1, when printed.
Finally, you should cast pointers to void * before printing:
printf("%p %p \n",(void *)((&s1.b)-1), (void *)&s1);
If the address of s1.b is 0x804a01c, then &s1.b-2 should be 0x804a014 (assuming that int is 4 bytes), not 0x804a018. Perhaps you made a mistake when you reported the address?
Thank you for posting your code. Now I see the issue. It is because of padding. To wit:
printf("sizeof(char): %d\n", sizeof(char));
printf("sizeof(short): %d\n", sizeof(short));
printf("sizeof(int): %d\n", sizeof(int));
printf("sizeof(struct st): %d\n", sizeof(struct st));
On my machine this prints
1
2
4
8
You might think, shouldn't sizeof(struct st) be 1 + 2 + 4 = 7? That's certainly a reasonable thought but because of alignment issues there is padding between a and c. Therefore, in memory, the struct looks like the following (relative to the first byte of the struct):
0x00000000: char a
0x00000001: padding
0x00000002: first byte of short c
0x00000003: second byte of short c
0x00000004: first byte of int b
0x00000005: second byte of int b
0x00000006: third byte of int b
0x00000007: fourth byte of int b
Consequently (relative to &s1):
&s1.b - 1 is ((long)&s1.b) - sizeof(int) = 4 - 4 = 0 = &s1
This is why both &s1 and &s1.b - 1 will print the same address. In particular if
&s1 = 0x804a01c
then
&s1.b = 0x804a01c + 0x00000004 = 0x804a020
and
&s1.b - 1 = 0x804a020 - 0x00000004 = 0x804a01c
and
&s1.b - 2 = 0x804a020 - 0x00000008 = 0x804a018
Note, finally, that this is implementation-specific behavior. This is not portable!