Can anyone explain the logic how to add a
and b
?
#include
int main()
{
int a=30000, b=20, sum;
char *p;
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)
/*
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;
}
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.
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
C standard says that E1[E2]
is equivalent to *((E1) + (E2))
. Therefore:
&p[b] = &*((p) + (b)) = ((p) + (b)) = ((a) + (b)) = a + 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.