Assigning address of an int to a char pointer - c

In the following program, suppose a is stored at address 1000 and an int takes up 4bytes of storage. Now, c will point to the base address ie, 1000 and incrementing it by 3 will make it point to address 1003. Now, printing the character pointed to by c must give me the character corresponding to ascii 65. But it prints nothing!
#include<stdio.h>
#include<stdlib.h>
int main(){
int a = 65;
char *c = &a;
printf("%c\n", *(c+3));
}
What is wrong in my reasoning?

You didn't take endianness into account. On a little-endian system, the 'a' (or if the encoding isn't ASCII compatible, whatever 65 is) will be in the first byte, and the other bytes are 0. Passing a 0 byte to printf("%c\n",_); prints out nothing but the newline.

printing the character pointed to by c must give me the character corresponding to ascii 65
It should and if your machine is little-endian, it will, indeed. However, you're printing the 4th byte of your int using *(c + 3), that's still 0. Perhaps you meant *c instead?
The best would be not aliasing stuff through pointers, however. Integers have the nice property that they can be operated on by bitwise operators.
uint32_t i = 0x12345678;
uint8_t b0 = (i >> 0) & 0xff;
uint8_t b1 = (i >> 8) & 0xff;
uint8_t b2 = (i >> 16) & 0xff;
uint8_t b3 = (i >> 24) & 0xff;
This will give you access to the bytes correctly regardless to the endianness of sour architecture.

Related

How to convert a char pointer array into a int pointer array in C

I have an 8 byte char pointer that has 2 integers stored inside it. how do I store it in a int array pointer so that the int array has the 1st integer is in array[0] and the 2nd integer is in array[1].
The code I made so far:
char * wirte_buff= (char*) malloc(8*sizeof(char*));
int i, j;
i = 16;
j = 18;
/*separates integer i and integer j into 4-bytes each*/
for(n=0; n<=3; n++){
wirte_buff[n] = (i >> 8*(3-n)) & 0xFF;
wirte_buff[4+n] = (j >> 8*(3-n)) & 0xFF;
}
int* intArray = (int*) wirte_buff; //puts char pointer to
printf("intArray[0] value is %d \n", intArray[0]);
printf("intArray[1] value is %d \n", intArray[1]);
When I did this it the expected result was 16 and 18, but I unexpectedly got 268435456 and 301989888.
Assuming you are aware of the strict aliasing rule violation, your code would generate the result you expect in a big endian architecture, in which the four bytes composing an integer are stored starting from the most significant byte:
------------------------------------------------------------------------------
| byte3 (bit 24:31) | byte2 (bit 16:23) | byte1 (bit 8:15) | byte0 (bit 0:7) |
------------------------------------------------------------------------------
But you are apparently running your code in a little endian architecture machine:
------------------------------------------------------------------------------
| byte0 (bit 0:7) | byte1 (bit 8:15) | byte2 (bit 16:23) | byte3 (bit 24:31) |
------------------------------------------------------------------------------
So, in order to displace your integer in the char array, you need that:
The byte 0 of i, that is i >> (8 * 0), is at index 0 of wirte_buff array
The byte 1 of i, that is i >> (8 * 1), is at index 1 of wirte_buff array
The byte 2 of i, that is i >> (8 * 2), is at index 2 of wirte_buff array
The byte 3 of i, that is i >> (8 * 3), is at index 3 of wirte_buff array
This translates in
wirte_buff[n] = (i >> 8*(n)) & 0xFF;
and the same, of course, for j:
wirte_buff[4+n] = (j >> 8*(n)) & 0xFF;
This code is wrong in many ways.
char * wirte_buff= (char*) malloc(8*sizeof(char*)); allocates 8 char* and no data. You don't assign these pointers anywhere, so they remain uninitialized.
i >> ... etc performs bitwise operations on a signed type, which is always wrong. If the value is negative, you end up with implementation-defined results.
Should you convert the int value into char, then char has implementation-defined signedness so you don't know if you end up with a negative value or possibly an overflow/underflow.
Should you avoid that as well, you can't read a char back through another type with (int*) wirte_buff; ... intArray[0] because these are not compatible types. You might read misaligned data. You will also violate strict pointer aliasing, see What is the strict aliasing rule?
There is no expected behavior of the posted code and I doubt you can salvage it. You will have to re-write this from scratch and especially avoid all the fishy conversions.

Storing int value into char p[] index

Been stuck on a problem. figured out my issue. I have looked online quite a bit and have read many possible solutions, but nothing seems to work for me.
I have this program, lets call it test.c
#include <stdio.h>
int main() {
int x = 21345;
char p[10];
p[0] = x;
printf("%d\n", x);
printf("%d", p[0]);
return 0;
}
As you would guess, I want the two printf statements to have the same output. Instead, I get the following output...
21345
97
I need 21345 to be at p[0], and when I call printf("%d", p[0]);
It needs to print out 21345, not 97
Any help? :(
EDIT:
Looks like you guys answered, thanks! Changing to int p[10] would solve the problem. I have another complication though, I also need to be able to store strings inside the indexes of p, along with ints.. how should I tackle this?
A char does not have the same type as int and is not identical in number of bits. You would need int p[10]; for that to work.
You have an array of signed chars, they take 1 byte each, the max value would be 127 and minimum -128. Now the x's value takes more bytes to represent, there is an overflow, and it truncates the leftmost bits,
21345 has the binary representation: 0101 0011 0110 0001
now discard the leftmost byte and you get: 0110 0001 which is 97
char store only 1 byte value so that you are getting that output. If you change char p[10] to int p[10] you will get output.
char is simply not big enough to store 21345. Therefore compiler takes just low 8 bits and puts them into char, so it becomes 97. When passing to printf it will convert it back to int but the highest bits are already lost.
You need to use int array instead of char
It should be like
#include <stdio.h>
int main() {
int x = 21345;
int p[10];
p[0] = x;
printf("%d\n", x);
printf("%d", p[0]);
return 0;
}
Output
21345
21345
Well if you want to use same array for strings too, use 2 dimensions char array
because you can store a integer value in 4 characters array correctly.
so you need to use p[10][4]
Now store each byte of int in corresponding char array index
p[0][0] = (x >> (8*0)) & 0xff;
p[0][1] = (x >> (8*1)) & 0xff;
p[0][2] = (x >> (8*2)) & 0xff;
p[0][3] = (x >> (8*3)) & 0xff;

fetch 32bit instruction from binary file in C

I need to read 32bit instructions from a binary file.
so what i have right now is:
unsigned char buffer[4];
fread(buffer,sizeof(buffer),1,file);
which will put 4 bytes in an array
how should I approach that to connect those 4 bytes together in order to process 32bit instruction later?
Or should I even start in a different way and not use fread?
my weird method right now is to create an array of ints of size 32 and the fill it with bits from buffer array
The answer depends on how the 32-bit integer is stored in the binary file. (I'll assume that the integer is unsigned, because it really is an id, and use the type uint32_t from <stdint.h>.)
Native byte order The data was written out as integer on this machine. Just read the integer with fread:
uint32_t op;
fread(&op, sizeof(op), 1, file);
Rationale: fread read the raw representation of the integer into memory. The matching fwrite does the reverse: It writes the raw representation to thze file. If you don't need to exchange the file between platforms, this is a good method to store and read data.
Little-endian byte order The data is stored as four bytes, least significant byte first:
uint32_t op = 0u;
op |= getc(file); // 0x000000AA
op |= getc(file) << 8; // 0x0000BBaa
op |= getc(file) << 16; // 0x00CCbbaa
op |= getc(file) << 24; // 0xDDccbbaa
Rationale: getc reads a char and returns an integer between 0 and 255. (The case where the stream runs out and getc returns the negative value EOF is not considered here for brevity, viz laziness.) Build your integer by shifting each byte you read by multiples of 8 and or them with the existing value. The comments sketch how it works. The capital letters are being read, the lower-case letters were already there. Zeros have not yet been assigned.
Big-endian byte order The data is stored as four bytes, least significant byte last:
uint32_t op = 0u;
op |= getc(file) << 24; // 0xAA000000
op |= getc(file) << 16; // 0xaaBB0000
op |= getc(file) << 8; // 0xaabbCC00
op |= getc(file); // 0xaabbccDD
Rationale: Pretty much the same as above, only that you shift the bytes in another order.
You can imagine little-endian and big-endian as writing the number one hundred and twenty tree (CXXIII) as either 321 or 123. The bit-shifting is similar to shifting decimal digtis when dividing by or multiplying with powers of 10, only that you shift my 8 bits to multiply with 2^8 = 256 here.
Add
unsigned int instruction;
memcpy(&instruction,buffer,4);
to your code. This will copy the 4 bytes of buffer to a single 32-bit variable. Hence you will get connected 4 bytes :)
If you know that the int in the file is the same endian as the machine the program's running on, then you can read straight into the int. No need for a char buffer.
unsigned int instruction;
fread(&instruction,sizeof(instruction),1,file);
If you know the endianness of the int in the file, but not the machine the program's running on, then you'll need to add and shift the bytes together.
unsigned char buffer[4];
unsigned int instruction;
fread(buffer,sizeof(buffer),1,file);
//big-endian
instruction = (buffer[0]<<24) + (buffer[1]<<16) + (buffer[2]<<8) + buffer[3];
//little-endian
instruction = (buffer[3]<<24) + (buffer[2]<<16) + (buffer[1]<<8) + buffer[0];
Another way to think of this is that it's a positional number system in base-256. So just like you combine digits in a base-10.
257
= 2*100 + 5*10 + 7
= 2*10^2 + 5*10^1 + 7*10^0
So you can also combine them using Horner's rule.
//big-endian
instruction = ((((buffer[0]*256) + buffer[1]*256) + buffer[2]*256) + buffer[3]);
//little-endian
instruction = ((((buffer[3]*256) + buffer[2]*256) + buffer[1]*256) + buffer[0]);
#luser droog
There are two bugs in your code.
The size of the variable "instruction" must not be 4 bytes: for example, Turbo C assumes sizeof(int) to be 2. Obviously, your program fails in this case. But, what is much more important and not so obvious: your program will also fail in case sizeof(int) be more than 4 bytes! To understand this, consider the following example:
int main()
{ const unsigned char a[4] = {0x21,0x43,0x65,0x87};
const unsigned char* p = &a;
unsigned long x = (((((p[3] << 8) + p[2]) << 8) + p[1]) << 8) + p[0];
printf("%08lX\n", x);
return 0;
}
This program prints "FFFFFFFF87654321" under amd64, because an unsigned char variable becomes SIGNED INT when it is used! So, changing the type of the variable "instruction" from "int" to "long" does not solve the problem.
The only way is to write something like:
unsigned long instruction;
instruction = 0;
for (int i = 0, unsigned char* p = buffer + 3; i < 4; i++, p--) {
instruction <<= 8;
instruction += *p;
}

Convert 4 bytes char to int32 in C

I first convert an int32 number to char[4] array, then convert the array back to int32 by (int *), but the number isn't the same as before:
unsigned int num = 2130706432;
unsigned int x;
unsigned char a[4];
a[0] = (num>>24) & 0xFF;
a[1] = (num>>16) & 0xFF;
a[2] = (num>>8) & 0xFF;
a[3] = num & 0xFF;
x = *(int *)a;
printf("%d\n", x);
the output is 127. And if I set num = 127, the output is 2130706432.
Does anyone have ideas?
Reverse the order of the a[] indexes, e.g,. a[0] -> a[3]
I think you have the endianness in reverse.
Try this:
a[3] = (num>>24) & 0xFF;
a[2] = (num>>16) & 0xFF;
a[1] = (num>>8) & 0xFF;
a[0] = num & 0xFF;
To see what happens use
printf("%x\n", ...);
to print both input and output number.
Endian-independent way:
x = (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3];
This line is never going to work correctly on a little-endian machine:
x = *(int *)a;
You need to unpack the data before you print out the value.
Your code a[0] = (num>>24) & 0xFF; takes the most significant 8 bits from num and sticks them in the first byte of a. On little endian machines the first byte holds the least signficant bits. That means that on little endian machines, this code takes the most significant 8 bits and stores them in the place where the least significant bits go, changing the value.
2130706432 is 0x7F000000 in hex, and 127 is 0x0000007F.
Also, x = *(int *)a; results in undefined behavior. Consider hardware where reading an int from an improperly aligned address causes a bus error. If a doesn't happen to be aligned properly for an int then the program would crash.
A correct approach to interpreting the bytes as an int would be std::memcpy(&x, a, sizeof x);

How to write a 24 bit message after reading from a 4-byte integer on a big endian machine (C)?

I am constructing a message to send a 24-bit number over the network.
For little endian machines, the code is (ptr is the pointer to the message buffer):
*ptr++ = (num >> 16) & 0xFF;
*ptr++ = (num >> 8) & 0xFF;
*ptr++ = (num) & 0xFF;
(So if num0, num1, num2 and num3 are the individual bytes making up num, the message would be encoded as num2|num1|num0.)
What should be the code for encoding num2|num1|num0 on a big endian machine?
The question here is, in what byte order shall the message be sent/constructed ? Because whether you are on a little or big endian machine doesn't matter with respect to num, as you're already dividing num into individual bytes in an endian-agnostic way.
The code you've posted stores 24 bits of num in big endian (aka network byte order). So if that's what you want you're already done. If you want to store it in big little instead, just reverse the order:
*ptr++ = (num) & 0xFF;
*ptr++ = (num >> 8) & 0xFF;
*ptr++ = (num >> 16) & 0xFF;
Your code is portable regardless of endianess. The shift operators >> << work with the values, not with the representation.
In the receiving machine, regardless of endian-ness, if you receive them in same order as they are stored in ptr, assemble them like this:
num = (ptr[0] << 16) + (ptr[1] << 8) + (ptr[2]);
int main(int argc, char** argv) {
int a, b;
a = 0x0f000000; // Contain 32 bit value
printf("before = %d\n", a);
b = a & (~0xff000000); // convert the last 8 bits to zero so we got only 24 bit value in b
printf("After = %d\n", b);
return (EXIT_SUCCESS);
}
There is a number containing a 32-bit value but number b contains only 24 bits, starting from least significant digit. And that doesn't depend on endianness because bitwise operators don't work with memory representation.
So you can use
num = num & (~0xff000000);
to get the last 24-bit value.

Resources