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;
}
Related
void main() {
int a = 2;
int *p = &a;
int *q = p++;
printf("%d %d\n", p, q);
int b = p - q;
printf("%d", b);
}
Why does it print 1? I've tried with other pointers but didn't succeed. I thought it would print the size of int because the distance between them is 1 * sizeof(int) but it prints 1.
why it prints 1?
Because C specifies pointer subtraction as the difference in the indexes (subscript) of the array, not the difference in address values.
1 past the object is like the an array element after the int a;
For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type. C17dr § 6.5.6 7
When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. The size of the result is implementation-defined, and its type (a signed integer type) is ptrdiff_t defined in the <stddef.h> header. § 6.5.6 8
Subscript 1 - subcript 0 --> 1.
The result is 1 even if int a was char a or long double a.
For starters according to the C Standard the function main without parameters shall be declared like
int main( void )
To output pointers you have to write
printf("%p %p\n", ( void * )p, ( void * )q);
In the initializer of the pointer q
int* q = p++;
there is used an expression with the postfix increment operator. Its value is the value of the operand before incrementing.
So the pointer q is initialized by the address of the variable a and as a side effect the pointer p is incremented and points to the memory after the object a. That is between the addresses (in the extent of memory bounded by these addresses) stored in the pointers p and q there is stored only one object a. So according to the pointer arithmetic the result of the expression p - q is 1.
On the other hand, the difference between the addresses stored in the pointers p and q is equal to the value of sizeof( int ) that is to the value of sizeof( a ).
If you will write for example
int b = ( char * )p - ( char * )q;
then the value of b will be equal to sizeof( a ) because in this case the memory occupied by the variable a is interpreted as a character array and sizeof( char ) is always equal to 1.
There are a few errors in this code:
The return type of main() should be int instead of void.
The printf() statement has two integer format specifiers, but the arguments passed are pointers, which are not guaranteed to have the same size as integers. Therefore, using the %d format specifier to print pointers is not correct. You can use the %p format specifier to print pointers.
The variables p and q are pointers to int, so the difference between them (i.e., p - q) should be divided by the size of int to get the number of elements between them.
Here is the corrected code:
#include <stdio.h>
int main() {
int a = 2;
int* p = &a;
int* q = p++;
printf("%p %p\n", p, q);
int b = (p - q) / sizeof(int);
printf("%d", b);
return 0;
}
This code will print the memory addresses of p and q, followed by the difference between them in terms of the number of int elements.
I need to know when the pointer went through the whole array -> is on the first position behind it.
Examplecode in c:
unsigned int ar[10];
char *pointer = (char*) ar;
while(pointer != (char*) &ar[10]){
*pointer++ = 0xff
}
Would this example work to set every element of the array to 0xffffffff?
The principle is right but you forgot to initialize the pointer and are incrementing it in the wrong place. Rather use
unsigned int ar[10];
unsigned char *pointer = (unsigned char *)ar;
unsigned char *end = (unsigned char *)&ar[10];
while (pointer != end) {
*pointer++ = 0xff;
}
if you increment the pointer in the comparison, then you will not set the first byte and will write one byte past the limit.
But never reinvent the wheel. There is a function in <string.h> for this:
unsigned int ar[10];
memset(ar, 0xff, 10 * sizeof (int));
// or if a static array,
memset(ar, 0xff, sizeof ar);
On the other hand, if you really want to set the unsigned ints to UINT_MAX, then you could be explicit:
for (size_t i = 0; i < 10; i++) {
ar[i] = UINT_MAX; // or you could use `-1` as well, as it is guaranteed to result in `UINT_MAX` after conversion.
}
When working with raw binary, I'd recommend to use an unsigned character type such as uint8_t instead of char, since the latter has implementation-defined signedness.
Then there are two special rules in C you can utilize:
C11 6.3.2.3/7
When a pointer to an object is converted to a pointer to a character type,
the result points to the lowest addressed byte of the object. Successive increments of the
result, up to the size of the object, yield pointers to the remaining bytes of the object.
This allows us to inspect or modify the raw binary contents of any type in C by using a character pointer. So you can indeed set every byte of the integer array to 0xFF using a character pointer.
The other special rule is hidden inside how the additive operators work, since the [] operator is just syntactic sugar around + and dereference. C11 6.5.6/8, emphasis mine:
If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.
This allows us to check the address 1 int beyond the end of the array.
However converting between a character type pointer and an int pointer creates misaligned pointers and that (at least in theory) invokes undefined behavior and possibly instruction traps. So you can't just cast the character pointer to an integer pointer and compare.
So the completely correct way would be to increase the character pointer by sizeof(int) then set 4 bytes each lap in the loop.
Meaning that the following is an well-defined (but cumbersome & hard-to-read) way of setting all bytes in the array:
#include <stdio.h>
#include <stdint.h>
int main (void)
{
unsigned int arr[10];
for(uint8_t* i = (uint8_t*)arr; (unsigned int*)i != &arr[10]; i+=sizeof(unsigned int))
{
i[0] = 0xFF;
i[1] = 0xFF;
i[2] = 0xFF;
i[3] = 0xFF;
}
for(size_t i=0; i<10; i++)
{
printf("%X\n", arr[i]);
}
return 0;
}
What is the point of typecasting into char ? Why not typecast it in int instead ?
#include <stdio.h>
int main()
{
int arr[15];
arr[1]=5;
arr[0]=2;
int diff = (char *)&arr[1] - (char *)&arr[0];
int diff2 = &arr[1] - &arr[0];
printf("%d\n%d", diff, diff2);
return 0;
}
Pointer arithmetic is not for the weak of heart, but always this will be true:
(&arr[0]/* pointer to first element*/)
+
(1 /* "next" */)
==
(&arr[1]/* pointer to second element*/)
This is true for any type, it is part of the rules of pointer arithmetic.
So it cannot be any other than
(&arr[1]/* pointer to second element */)
-
(&arr[0]/* pointer to first element */)
==
1
which is of course exactly like
diff2 == 1
This is not changed if the result of & is cast to a pointer to the actual type of the array entries, in this case int and int*. With that +1 still means "next array entry".
On the other hand
(char *)&arr[0]
is bend to be a pointer to something different than the type of the entries of the array. It has been forced to be a pointer to a char. If you increase that by one, it has to be a pointer to the next char and
(char *)&arr[0] + N
==
(char *)&arr[1]
can only be true, if N is the number of chars between the addresses of two consecutive array entries.
So
N =
(char *)&arr[1] - (char *)&arr[0]
ensures it.
To understand this let us take a simple example:-
#include <stdio.h>
int main()
{
int arr[3]={1,2,3};
int *p=arr;
for(int i=0;i<3;i++){
printf("%d ",*p);
p++; // In this line p is an address.
//Here address is incremented by 1.
// But the logic is that 1 is an integer.
// If 1 might not be an integer then the result should not be like this.
// Same is in your case if you are storing difference of two addresses
// in an integer then it calculates the difference
// with respect to the type of address(int in your case).
}
return 0;
}
In c++ if integer is used with addresses for any operation then its calculations are totally based upon the type of address(int,void,float....).
This is in C. I am learning C and this is an example in a slide from class.
int main(int argc, char *argv[]) {
int a = 5, b = 10, c;
int *p = &a, *q = &b;
c = p - q;
printf("%d", c);
return 0;
}
The output when I run it is 3 and I don't understand why. It seems like since it is using & it would subtract to memory addresses and the output would be a memory address to -5.
You are subtracting the address of the pointers not what they are pointing to and you'll get whatever the difference is between the two memory addresses is which is not guaranteed to be anything specific. If you run it on a different machine or compiler it will most likely be totally different values as a and b can be assigned a variety of addresses. For example on my machine it is 1. A phenomenons like this are called undefined behavior for a reason as you cannot guarantee the same result across all compilers and machines.
If you instead dereferenced p and q like this c = *p - *q; you would get -5 as c as the difference between the two set vales. Also if you assigned p and q as int *p = a, *q = b; then you would also get c as -5 because then you are literally setting the pointers to different address and trying to access after doing something like that will in all cases be a terrible idea.
Subtracting 2 pointers that are not of the same array is undefined behavior.
When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. C11 §6.5.6 9
Instead, to get some numeric difference, convert values to intptr_t.
int main(int argc, char *argv[]) {
int a = 5, b = 10, c;
int *p = &a, *q = &b;
intptr_t ip = (intptr_t) p;
intptr_t iq = (intptr_t) q;
intptr_t diff = ip -iq;
printf("%lld", (long long) diff);
return 0;
}
Of course the value you print may not be 5. The locations of the int vary from compile to compile.
I encountered some code in a tutorial about buffer overflows.
It's a program that exploits a simple program that is vulnerable to a buffer overflow (if some stack protection mechanisms are turned off).
My question is: what is the for loop doing? I mean the line within the for loop:
*(void **)(buf + i) = addr;
Its a bit of a strange syntax that I haven't seen before, or maybe I have seen it but it just confuses me.
The idea of the program is that the buf is passed as argument to the vulnerable program and through a strcpy it will overwrite the return address on the stack such that it will run the shellcode that is passed in an environment parameter.
Thanks!
The full code:
int main(int argc, char **argv) {
void *addr = (char *) 0xc0000000 - 4 - (strlen(VULN) + 1) - (strlen(&shellcode) + 1);
char buf[768];
size_t i;
for (i = 0; i < sizeof(buf); i += sizeof(void *)) {
*(void **)(buf + i) = addr;
}
char *params[] = { VULN, buf, NULL };
char *env[] = { &shellcode, NULL };
execve(VULN, params, env);
perror("execve");
return -1;
}
C has a kind of Treehorn type system. For any object x of type T, you can pretend it's an object of a different type. To do so, you cast the address of the object. So, in steps:
T x; is an object of type T.
&x is the address of the object, it's of type T * – "pointer to T".
Now pretend this is a pointer to something else: (U *)(&x) – a "pointer to U", but it's the same value.
If we dereference that, we treat the object x as though it were a U: *(U *)(&x)
Now apply all this to T = char, x = buf[i] and U = void * in your code. Note that &buf[i] is identical to buf + i. Also note that i is incremented in strides of sizeof(void *) so that each round of the loop doesn't step on the memory touched by the previous rounds.
A word of warning: it is generally not allowed to treat one object as though it were one of a different type; this is undefined behavior. There are only some exceptions; e.g. you can treat an int as though it were an unsigned int, and you can treat any object x as though it were a char[sizeof x]. (None of these are the case in your code, which is not well-formed.)
First, it calculates a value which will remain constant throughout the execution of the for loop:
0xc0000000 - 4 - (strlen(VULN) + 1) - (strlen(&shellcode) + 1)
Then, inside the for loop, it writes this constant value into every "4-byte entry" in the buf array:
buf[0...3] = the constant value
buf[4...7] = the constant value
buf[8...11] = the constant value
...
buf[764...767] = the constant value