C union char array prints 'd' on mac? - c++

I am new to C/C++, but was curious to know about the issue i am seeing.
typedef union
{
int a;
float c;
char b[20];
}
Union;
int main()
{
Union y = {100};
printf("Union y :%d - %s - %f \n",y.a,y.b,y.c);
}
And output is
Union y :100 - d - 0.000000
My question is ...why is 'd' getting printed? I changed the order in union still the same output. but if i declare a char f[20] outside the union then nothing gets printed.
I am having MacBook lion image and using xcode.
THanks in advance

The ASCII code for 'd' is 100. Setting a to 100 amounts to setting b to {'d', '\0', '\0', '\0', …noise…} (on a 32-bit little-endian machine), which printf treats as "d".

The following program may help you understand better:
#include <stdio.h>
typedef union
{
int a;
float c;
char b[20];
}
Union;
void dump(const void* buffer, size_t length)
{
size_t i;
for (i = 0; i < length;) {
printf("%.2x ", reinterpret_cast<const unsigned char*>(buffer)[i]);
++i;
if (i % 16 == 0) {
putchar('\n');
} else if (i % 8 == 0) {
putchar(' ');
}
}
if (i % 16 != 0) {
putchar('\n');
}
}
int main()
{
Union y = {100};
printf("Union y :%d - %s - %f \n",y.a,y.b,y.c);
printf("The content of the Union is: \n");
dump(&y, sizeof y);
}
The output is:
Union y :100 - d - 0.000000
The content of the Union is:
64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00
Effectively, the binary representation of a (which is a int) is 64 00 00 00, 100 in little-endian hexadecimal. The binary representation of b is 64 00 ..., and the 0x00 ends the string, while 0x64 is 'd'. The binary representation of c is 64 00 00 00, which in the IEEE float representation is 0.0, because the non-zero part is the exponent.

I changed the order in union still the same output.
The order of the elements in a union doesn't change anything because all the elements of a union use the same piece of memory. Your code prints 100 for y.a and d for y.b because both expressions interpret the same bytes. So, for example, if you add a line that sets y.b and then prints again:
Union y = {100};
printf("Union y :%d - %s - %f \n",y.a,y.b,y.c);
y.b = 'f';
printf("Union y :%d - %s - %f \n",y.a,y.b,y.c);
you'll see that y.a and y.c. change whenever y.b changes, and vice versa. y.a should change to 102 in the second printf(), since that's the ASCII character code for 'f'.

Related

Values of padding bytes in C

I've spotted a strange behavior in this small C program. I have 2 structures, both with padding bytes, but in different places.
The first structure has padding bytes with indices [1:3], and the output is expected: static variables are zeroed-out, so padding values are all 0, local variables on stack are left with garbage values in padding bytes. Example output:
Char is first, then int:
aa 60 8e ef ff ff ff ff
aa 00 00 00 ff ff ff ff
But in the second structure, something strange happens. Padding bytes in this structure are with indices [5:7], so I expected some garbage values in non-static variable, but every time the output is:
Int is first, then char:
ff ff ff ff aa 7f 00 00
ff ff ff ff aa 00 00 00
Why the padding is always 7f 00 00?
The complete program:
#include "stdio.h"
#include "stdint.h"
#include "stddef.h"
// 0 1 2 3 4 5 6 7
// |a|#|#|#|b|b|b|b|
typedef struct
{
uint8_t a;
uint32_t b;
} S1;
// 0 1 2 3 4 5 6 7
// |a|a|a|a|b|#|#|#|
typedef struct
{
uint32_t a;
uint8_t b;
} S2;
void print_bytes(void* mem, size_t num_bytes)
{
for (size_t i = 0; i < num_bytes; i++)
printf("%02x ", *((unsigned char*)mem + i));
putc('\n', stdout);
}
int main()
{
S1 var1 = { .a = 0xAA, .b = 0xFFFFFFFF };
static S1 var1_s = { .a = 0xAA, .b = 0xFFFFFFFF };
printf("Char is first, then int:\n");
print_bytes(&var1, sizeof(S1));
print_bytes(&var1_s, sizeof(S1));
S2 var2 = { .a = 0xFFFFFFFF, .b = 0xAA };
static S2 var2_s = { .a = 0xFFFFFFFF, .b = 0xAA };
printf("\nInt is first, then char:\n");
print_bytes(&var2, sizeof(S2));
print_bytes(&var2_s, sizeof(S2));
}
There's no problem if I run your program. Last bytes are random. It likely depends on your system.

Problems reading binary file

I'm trying to read the first 6 bytes of a file, but it's giving me weird results, and I can't seem to figure out what I'm doing wrong.
My code:
struct Block {
char fileSize[3];
char initialDataBlockId[3];
};
int main(int c, char **a) {
ifstream file("C\\main_file_cache.idx0", ios::binary);
Block block;
file.get((char*)&block, sizeof(block));
printf("File Size: %i\n", block.fileSize);
printf("Initial Data Block ID: %i\n", block.initialDataBlockId);
file.close();
system("pause");
return 0;
}
Before I ran the code, I opened the file in a binary editor,
and it showed me this hex code:
00 00 00 00-00 00 05 af-4b 00 00 01-26 df cd 00
00 6f 03 3f-ed 00 03 61-05 08 35 00-04 8b 01 61
59 00 08 39-03 23 0a 00-05 6c 00 35-d0 00 06 fe
03 69 d8 00-07 19
There are a total of 54 bytes. The first 6 bytes are just zero.
So, I expected my program to produce the following output:
File Size: 0
Initial Data Block ID: 0
Instead, the outputs is as follows:
File Size: 10419128
Initial Data Block ID: 10419131
This result makes no sense. Maybe there is something wrong with my code?
You should use type unsigned char in your Block structure.
You should use file.read() to read binary data instead of file.get().
You are printing the addresses of the arrays in the Block structure, not their contents, furthermore the specifier %i expects an int, not a char *, so the behavior in undefined and you get some weird integer value but anything culd have happened, including program termination. Increasing the warning level is advisable so the compiler warns about such silly mistakes.
If the file format is little endian, you could convert these 3 byte arrays to numbers this way:
int block_fileSize = (unsigned char)block.fileSize[0] +
((unsigned char)block.fileSize[1] << 8) +
((unsigned char)block.fileSize[2] << 16);
int block_initialDataBlockId = (unsigned char)block.initialDataBlockId[0] +
((unsigned char)block.initialDataBlockId[1] << 8) +
((unsigned char)block.initialDataBlockId[2] << 16);
printf("File Size: %i\n", block_fileSize);
printf("Initial Data Block ID: %i\n", block_initialDataBlockId);
If you want to read a binary data you can use a read method from ifstream and also write method from ofstream.
istream & ifstream::read (char * s, streamsize n);
ostream & ofstream::write (const char * s, streamsize n);
You have to know that binary mode is useless for UNIX systems and text mode is only useful.

Disable alignment on a 64-bit structure

I'm trying to align my structure and make it as small as possible using bit fields. I have to send this data back to a client, which will examine the fields to set a few data members.
The size of the structure is indeed the same, but when I set members it does not work at all.
Here's some example code:
#pragma pack(push, 1)
struct PW_INFO
{
char hash[16]; //Does not matter
uint32_t number; //Does not matter
uint32_t salt_id : 30; //Position: 0 bits
uint32_t enc_level : 7; //Position: 30 bits
uint32_t delta : 27; //Position: 37 bits
}; //Total size: 28 bytes
#pragma pack(pop)
void int64shrl(uint64_t& base, uint32_t to_shift, uint32_t position)
{
uint64_t res = static_cast<uint64_t>(to_shift);
res = Int64ShllMod32(res, position);
base |= res;
}
int32_t main()
{
std::cout << "Size of PW_INFO: " << sizeof(PW_INFO) << "\n"; //Returns 28 as expected (16 + sizeof(uint32_t) + 8)
PW_INFO pw = { "abc123", 0, 0, 0, 0 };
pw.enc_level = 105;
uint64_t base{ 0 };
&base; //debug purposes
int64shrl(base, 103, 30);
return 0;
}
Here's where it gets weird: setting the "salt_id" field (which is 30 bits into the bitfield) will yield the following result in memory:
0x003FFB8C 61 62 63 31 32 33 00 00 abc123..
0x003FFB94 00 00 00 00 00 00 00 00 ........
0x003FFB9C 00 00 00 00 00 00 00 00 ........
0x003FFBA4 69 00 00 00 i...
(Only the last 8 bytes are of concern since they represent the bit field.)
But, Int64ShllMod32 returns a correct result (the remote client undersands it perfectly):
0x003FFB7C 00 00 00 c0 19 00 00 00 ...À....
I'm guessing it has to do with alignment, if so how would I completely get rid of it? It seems even if the size is correct, it will try to align it (1 byte boundary as the #pragma directive suggests).
More information:
I use Visual Studio 2015 and its compiler.
I am not trying to write those in a different format, the reason I'm asking this is that I do NOT want to use my own format. They are reading from 64 bit bitfields everywhere, I don't have access to the source code but I see a lot of calls to Int64ShrlMod32 (from what I read, this is what the compiler produces when dealing with 8 byte structures).
The actual bitfield starts at "salt_id". 30 + 7 + 27 = 64 bits, I hope it is clearer now.

vector or array value insertion

I have a variable
long long int alpha;
This alpha is basically 8 bytes
but I wish the byte size can be decided dynamically by input to the function.
So that it could be inserted to char* array.
If there is a function
int putInput(int sizeOfAlpha){
long long int alpha;
char* beta = (char*)malloc(128);
for(int i = 0 ; i < 128 ; i++){
... alpha calculation ...
beta[i*sizeOfAlpha] = alpha; // This is also wrong
}
}
Then the size of alpha has to be modified by sizeOfAlpha
For instance if sizeOfAlpha is 2 in decimal,
and if alpha is 0x00 00 00 00 00 00 04 20 in hex,
and if i is 0 ,
then beta[0] should be 04 and beta[1] should be 20 in hex
if alpha is 0x00 00 00 00 00 00 42 AB in hex,
and if i is 1 ,
then beta[2] should be 42 and beta[3] should be AB in hex
Can anyone help me with this?
Assuming alpha is unsigned :
std::vector<std::uint8_t> vec(8);
for(std::size_t j = (i + 1u) * sizeOfAlpha - 1u; sizeOfAlpha; --j, --sizeOfAlpha) {
vec[j] = alpha & 0xff;
alpha >>= 8;
}
Live on Coliru

processing a raw hex communication data log into readable values

I have an embedded microcontroller system that is communicating to my computer via uart, and at this point of development is should be sending out valid data on its own. I have triggered a 'scan' of this device, its role then is to send out data it's read to the host device autonomously. I now have a text file with raw hex data values in there, ready to be processed. I'm sending out packets that start with 0x54 and end in 0x55 and they come in lots of 4 (4 packets per single 'read' of the instrument). A packet contains two 'identifier' bytes after the 0x54, then a bunch of 6 bytes for data, totaling 10 bytes per packet. depending on the packet identifiers, the data within could be a floating point number or an integer.
I basically want to to design a command line program that takes in a raw text file with all this data in it, and outputs a text file, comma seperated between packets, with the data converted to its readable decimal counterpart. a new line for every 4th converted packet would be very useful. I'd like to do this in C (I am relatively proficient in coding embedded C, and I can convert the hex values back and forth between types easily enough) but I do not have much experience in writing C executables. Any help with getting started on this little mini project would be awesome. I need to know how to create a command line controllable executable, read in a data file, manipulate the data (which I think I can do now) and then export the data to another file. I've installed netbeans c/c++. Pointers in the right direction are all I require (no pun intended =] )
Here's the raw data file:
http://pastebin.com/dx4HetT0
There is not much variation in the data to deduce the bytes with certainty, but the following should get the OP started.
void db_parse(FILE *outf, const unsigned char *s) {
fprintf(outf, "%c", *s++);
fprintf(outf, " %3u", *((uint8_t *) s));
s += sizeof(uint8_t);
uint8_t id1 = *((uint8_t *) s);
fprintf(outf, " %3u", *((uint8_t *) s));
s += sizeof(uint8_t);
if (id1 >= 3) {
fprintf(outf, " %13e", *((float *) s));
s += sizeof(float);
} else {
fprintf(outf, " %13u", *((uint32_t *) s));
s += sizeof(uint32_t);
}
fprintf(outf, " %5u", *((uint16_t *) s));
s += sizeof(uint16_t);
fprintf(outf, " %c\n", *s);
}
// Test code below
const char *h4 =
"54 12 04 00 00 40 C0 00 00 55 54 12 01 02 00 00 00 00 00 55 54 12 02 03 00 00 00 00 00 55 54 12 03 00 00 40 C0 00 00 55 ";
void db_test() {
unsigned char uc[10];
const char *s = h4;
while (*s) {
for (int i = 0; i < 10; i++) {
unsigned x;
sscanf(s, "%x", &x);
uc[i] = x;
s += 3;
}
db_parse(stdout, uc);
}
}
Output
T 18 4 -3.000000e+00 0 U
T 18 1 2 0 U
T 18 2 3 0 U
T 18 3 -3.000000e+00 0 U