/*
* Change the value pointed to by ptr byte-by-byte so that when returned as an
* integer the value is 351351.
*
* Hints: Recall that an int is 4 bytes and how little-endian works for
* multibyte memory storage. We suggest starting by converting 351351 into
* binary/hexadecimal.
*
* ALLOWED:
* Pointer operators: *, &
* Binary integer operators: -, +, *
* Shorthand operators based on the above: +=, *=, ++, --, etc.
* Unary integer operators: !
*
* DISALLOWED:
* Pointer operators: [] (Array Indexing Operator)
* Binary integer operators: &, &&, |, ||, <, >, <<, >>, ==, !=, ^, /, %
* Unary integer operators: ~, -
*/
I need to write a function following the requirements above. I can't use loops, or array indexing, and other stuff. I understand the endianness concept. So I have integer 351351. In hex it is 0x 00 05 5C 77
. So with the little endian machine, it would be stored as 77 5C 05 00
, right?
int endianExperiment(int * ptr) {
char * bytePtr;
// Your code here
// 0x 00 05 5C 77
int num = 0;
bytePtr = (char * ) ptr;
return num;
}
This is my function so far. I got the address of the pointer parameter in char (so only 2 bytes) then stored it in bytePtr. But I am stuck after. I tried several options, and nothing works. Please help.
Also, so with little-endian, the number is stored with a least significant digit at the lowest index in array. But to access it (address of the digit), is it still the lowest index? Or is it the index that contains the first byte? Where do I need to have pointer point to?
The "disallowed" list makes a lot of restrictions. For instance, a usual approach is to bitmask (&) and bitshift (<<, >>) the bytes into opposite endian position, but these operations are disallowed. Remainder (%) is also disallowed, which we otherwise could use to emulate bitmasking. So what's left? It sounds like an allowed approach is the following (and hinted at by asking that the value be changed "byte-by-byte"):
Start by punning the input to a char* pointer as you have done: char* bytePtr = (char*)ptr
. Assuming little endian native byte order, *bytePtr
is the least significant byte of integer *ptr
.
Make a pointer to the most significant byte of num: char* dest = ((char*)&num) + 3
.
Assign *bytePtr
to *dest
. That's one byte done.
Increment bytePtr
and decrement dest
.
Repeat steps 3 and 4 three more times for the remaining bytes. But don't use a loop to do that, since <
is disallowed, just write out the repetitions unrolled.
At the end, num
contains the integer with reversed endianness.
Edit: I may have misunderstood the intention. Thanks to busybee for pointing this out. Re-reading, the problem statement is "Change the value pointed to by ptr byte-by-byte so that when returned as an integer the value is 351351."
It sounds like we should write the specific int value 351351 to *ptr
. And, we should do so byte-by-byte---it would be too easy if we could just do *ptr = 351351
.
The hexadecimal form of 351351 is 0x00055c77 like Roman said.
Supposing the machine is little endian, write the bytes 0x77, 0x5c, 0x05, 0x00, starting in the lowest address with 0x77: *bytePtr = 0x77
, *(bytePtr + 1) = 0x5c
, and so on.
However, if the machine is big endian, the bytes need to be in the reverse order so that *ptr == 351351
when interpreted as an int value: *bytePtr = 0x00
, *(bytePtr + 1) = 0x05
, and so on.
It's a good idea to write code portably to work on both little endian and big endian machines. There are multiple methods to detect the endianness of the machine, including some that work in C with the allowed operations. So we could detect little vs. big endianness, then proceed to write the bytes as described above in the appropriate order. (Endianness other than little and big are also possible, and a comprehensive solution could handle them as well, but nowadays they are rare.)