Can somebody explain to me what happens with br agument in union, after assigning str.a and str.b? We need to set that value before calling the function above? I tried to run the code in simulator https://pythontutor.com/render.html#mode=display which says that the value of br is 516 before calling the function. How is that possible?
#include <stdio.h>
void f(short num, short* res){
if (num){
*res = *res * 10 + num%10;
f(num / 10, res);
}}
typedef union {
short br;
struct {
char a, b;
} str;
} un;
void main() {
short res = 0; un x;
x.str.a = 4; x.str.b = 2;
f(x.br, &res); x.br = res;
printf("%d %d %d\n", x.br, x.str.a, x.str.b);}
Assuming that char is one byte and short is two bytes (the most common), then it's really simple.
Begin by drawing out the members of the union on a piece of paper, one member next to the other. Something like this:
br str
+---+ +---+
| | | | a
+---+ +---+
| | | | b
+---+ +---+
Now we do the assignments:
x.str.a = 4;
x.str.b = 2;
And write the results in the drawing:
br str
+---+ +---+
| 4 | | 4 | a
+---+ +---+
| 2 | | 2 | b
+---+ +---+
Assuming little endianness like on a normal x86 or x86-64 system, then the value of br will be 0x0204 which is 516 in decimal.
So that's where the value 516 is coming from.
The value of the short will depend on the computer's endianess. On a little endian machine, a will correspond to the least significant byte and b to the most significant. Thus when those two bytes are converted to a short, you get the number 0x0204 = 516 decimal.
As a side note, it is a bad idea to use short and char since those may be signed and negative. Use uint16_t and uint8_t instead, whenever dealing with binary arithmetic.
If you put some effort into your debugging you would see what is going on:
void f(short num, short* res)
{
if (num)
{
*res = *res * 10 + num%10;
f(num / 10, res);
}
}
typedef union
{
short br;
struct
{
char a, b;
};
} un;
int main(void)
{
short res = 0; un x;
x.a = 4; x.b = 2;
printf("Before br=0x%04x (%d) a=0x%02x b=0x%02x res = %d 0x%x\n", x.br, x.br, x.a, x.b, res, res);
f(x.br, &res); x.br = res;
printf("After br=0x%04x a=0x%02x b=0x%02x res = %d 0x%x\n", x.br, x.a, x.b, res, res);
}
result:
efore br=0x0204 (516) a=0x04 b=0x02 res = 0 0x0
After br=0x0267 a=0x67 b=0x02 res = 615 0x267
Do your br was 516 and it was reversed by the f function becoming 615 which is 0x0276. It contains of two bytes 0x02 and 0x67.
Your computer is little-endian so the first byte is 0x67 and the second one is 0x02 because this system stores the least significant byte first.
Related
I am trying to align compound literal to 16 bytes.
I found this
which is :
#define ALIGNED_STRING(S) (struct { _Alignas(16) char s[sizeof S]; }){ S }.s
char *u = ALIGNED_STRING("agsdas");
which compiles.
and tried to apply it to uint32_t.
I tried this so far with gcc.
#define BLOCK_ALIGNED_U32(...) (struct { _Alignas(16) uint32_t x[sizeof ((uint32_t[]){__VA_ARGS__})]; }){ __VA_ARGS__ }.x
uint32_t toto[] = BLOCK_ALIGNED_U32(0x11111111, 0x22222222);
and even:
uint32_t tata[] = (struct { uint32_t __attribute__((aligned(16))) x[2]; }){.x = {0x11111111, 0x22222222}}.x;
but it gives me error : invalid initializer
What am I doing wrong / missing?
note: I am doing this because I want to control the aligment of some data block inside a structure declaration, like this:
struct
{
uint32_t* foo1;
uint32_t* foo2;
uint32_t* foo3;
uint32_t* foo4;
}s_t;
s_t foo[]=
{
.foo1 = BLOCK_ALIGNED_U32(1,2,3),
.foo2 = BLOCK_ALIGNED_U32(2,2),
.foo3 = (uint32_t[]){1,2,3},//could be not 16-bytes-aligned
.foo4 = (uint32_t[]){2,2},//could be not 16-bytes-aligned
}
At least these issues:
OP's macro array sizing was wrong.
// uint32_t x[sizeof ((uint32_t[]){__VA_ARGS__})]
uint32_t x[sizeof ((uint32_t[]){__VA_ARGS__}) / sizeof(uint32_t)]
Add { }
// OP's
#define ALIGNED_U32(...) (struct { _Alignas(16) uint32_t x[sizeof ((uint32_t[]){ __VA_ARGS__}) ]; }){ __VA_ARGS__ }.x
// Suggested fix
#define ALIGNED_U32(...) (struct { _Alignas(16) uint32_t x[sizeof ((uint32_t[]){ __VA_ARGS__})/sizeof(uint32_t)]; }){ { __VA_ARGS__ } }.x
Sample usage
#define ALIGNED_U32(...) (struct { _Alignas(16) uint32_t x[ \
sizeof ((uint32_t[]){ __VA_ARGS__ })/sizeof(uint32_t) \
]; }) { .x = { __VA_ARGS__ } }.x
typedef struct {
uint32_t *foo1;
uint32_t *foo2;
uint32_t *foo3;
uint32_t *foo4;
} s_t;
s_t foo = { //
.foo1 = ALIGNED_U32(1, 2, 3), //
.foo2 = ALIGNED_U32(2, 2), //
.foo3 = (uint32_t[]) {1, 2, 3}, // might be not 16-bytes-aligned
.foo4 = (uint32_t[]) {2, 2}, // might be not 16-bytes-aligned
};
Alignment is determined by the type of the object and directives associated with the object itself. It isn't determined by the value from which it is initialized.
In other words, there's nothing you can place on the right of uint32_t foo[] = that will affect how the array or individual elements of the array are aligned.
Let's compare.
In the linked post
char *u = ALIGNED_STRING("agsdas");
This produces two objects.
u <anon>
alignment = char* alignment = 16
+----------------+ +---+---+---+-...-+
| -------------->| a | g | s | ... |
+----------------+ +---+---+---+-...-+
As you can see, ALIGNED_STRING has no effect on the alignment of the variable (u), just the alignment of the anon object to which u will point.
In your post
uint32_t foo[] = ...;
This produces a single object.
foo
alignment = uint32_t[] = uint32_t
+----------------+
| |
+----------------+
| |
+----------------+
| |
⋮ ⋮
| |
+----------------+
If you had an array of pointers to uint32_t, you could align those uint32_t as you wish.
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
int main( void ){
_Alignas( 16 ) uint32_t i1 = 1;
_Alignas( 16 ) uint32_t i2 = 2;
uint32_t i3 = 3;
uint32_t i4 = 4;
uint32_t *ptrs[] = {
&i1,
&i2,
&i3,
&i4,
};
size_t n = sizeof(ptrs)/sizeof(*ptrs);
for ( size_t i=0; i<n; ++i ) {
uint32_t *ptr = ptrs[i];
printf( "%p %" PRIu32 "\n", (void *)ptr, *ptr );
}
}
We can even make those object anonymous. Anonymous objects can be created using the ( type ){ initializer body } syntax, and can use _Alignas as part of the type to align the object.
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#define ALIGNED_UINT32( S, I ) ( ( _Alignas( S ) uint32_t ){ I } )
#define ANON_UINT32( I ) ( ( uint32_t ){ I } )
int main( void ){
uint32_t *ptrs[] = {
&ALIGNED_UINT32( 16, 1 ),
&ALIGNED_UINT32( 16, 2 ),
&ANON_UINT32( 3 ),
&ANON_UINT32( 4 ),
};
size_t n = sizeof(ptrs)/sizeof(*ptrs);
for ( size_t i=0; i<n; ++i ) {
uint32_t *ptr = ptrs[i];
printf( "%p %" PRIu32 "\n", (void *)ptr, *ptr );
}
}
Both of the above produce five objects.
ptrs
alignment = uint32_t*
+----------------+ +---+---+---+---+ i1/<anon>
| -------------------------->| 1 | alignment = 16
+----------------+ +---+---+---+---+
| ----------------------+
+----------------+ | +---+---+---+---+ i2/<anon>
| -----------------+ +--->| 2 | alignment = 16
+----------------+ | +---+---+---+---+
| ------------+ |
+----------------+ | | +---+---+---+---+ i3/<anon>
| +-------->| 3 | alignment = uint32_t
| +---+---+---+---+
|
| +---+---+---+---+ i4/<anon>
+------------->| 4 | alignment = uint32_t
+---+---+---+---+
Sample run:
0x7ffe29b31b30 1
0x7ffe29b31b20 2
0x7ffe29b31b1c 3
0x7ffe29b31b18 4
Demo on Compiler Explorer
#include <stdio.h>
int main()
{
int x = 1023;
char *p = (char *)&x;
printf("%d %d %d %d\n", p[0], p[1], p[2], p[3]);
}
The result is: -1 3 0 0
I have imagined:
int x = 1023 (4 bytes):
m m+1 m+2 m+3
-+----+----+----+----+----+----+-
| | 255| 3 | 0 | 0 | |
-+----+----+----+----+----+----+-
~~~~~~~~~~~~~~~~~~~~~
cast to char pointer:
m
-+----+----+----+----+----+----+-
| | 255| 3 | 0 | 0 | |
-+----+----+----+----+----+----+-
~~~~~~
Why is the result -1 3 0 0? Or where did I go wrong?
char can be either signed char or unsigned char, it's implementation-dependent. Your implementation uses signed char. The values range from -128 to 127, 255 is not a possible value. That byte representation corresponds to -1.
Change your pointer declaration to
unsigned char *p = (unsigned char*)&x;
and you'll get the result you expect.
In the following code
#include <stdio.h>
int main() {
union a {
int i;
char ch[2];
};
union a u;
int b;
u.ch[0] = 3;
u.ch[1] = 2;
printf("%d,%d,%d\n", u.ch[0], u.ch[1], u.i);
return 0;
}
The output I get is
3,2,515
Can anyone explain me why the value of i is 515?
union a {
int i;
char ch[2];
};
union a u; /* initially it contains gargage data */
All members of the union shares the common memory. In above case total of 4 bytes gets allocated for u because in 4 bytes(MAX memory needed) you can store both i and ch.
ch[1] ch[0]
----------------------------------
| G | G | G | G | => G means garbage/junk data, because u didn't initialized
----------------------------------
u
MSB LSB
when statement u.ch[0] = 3; executed only ch[0] initialized.
ch[1] ch[0]
--------------------------------------
| G | G | G | 0000 0011 | => G means garbage/junk data, because u didn't initialized
--------------------------------------
u
MSB LSB
And when u.ch[1] = 2; executed next 1 bytes gets initialized as
ch[1] ch[0]
------------------------------------------
| G | G | 0000 0010 | 0000 0011 | => G means garbage/junk data, because u didn't initialized
------------------------------------------
u
MSB LSB
As you can see above out of 4 bytes only first 2 bytes got initialized, still remaining 2 bytes are uninitialised so when you are printing u.i, its undefined behaviour.
If you want expected result then initialize then union variable first as
union a u = { 0 }; /* all 4 bytes got initialized at first instance itself, no chance of any junk data */
u.ch[0] = 3;
u.ch[1] = 2;
Now when you prints u.i, it prints data in whole 4 bytes which is 512 + 3 = 515 (In case of little enidian processor)
I have a function that return 1 Byte
uint8_t fun();
the function should run 9 times , so I get 9 Byte I want to make the last8 one as 4 short values here what I've done but I'm not sure that the value that I get are correct :
char array[9];
.............
for ( i = 0; i< 9 ; i++){
array[i] = fun();
}
printf( " 1. Byte %x a = %d , b=%d c =%d \n" ,
array[0],
*(short*)&(array[1]),
*(short*)&(array[3]),
*(short*)&(array[5]),
*(short*)&(array[7]));
is that right ?
It's better to be explicit and join the 8-bit values into 16-bit values yourself:
uint8_t bytes[9];
uint16_t words[4];
words[0] = bytes[1] | (bytes[2] << 8);
words[1] = bytes[3] | (bytes[4] << 8);
words[2] = bytes[5] | (bytes[6] << 8);
words[3] = bytes[7] | (bytes[8] << 8);
The above assumes little-endian, by the way.
You will get alignement problems. Any pointer to a short can be seen as a pointer to char, but on non 8 bit machines, the inverse is not guaranteed.
IMHO, this would be safer :
struct {
char arr0;
union {
char array[8];
uint16_t sarr[4];
} u;
} s;
s.arr0 = fun();
for ( i = 0; i< 8 ; i++){
s.u.array[i] = fun();
}
printf( " 1. Byte %x a = %d , b=%d c =%d d=%d\n" ,
s.arr0,
s.u.sarr[0],
s.u.sarr[1],
s.u.sarr[2],
s.u.sarr[3]);
But I suppose you deal correctly with endianness on your machine and know how the conversion 2 chars <=> 1 short works ...
Try using struct to arrange the data and shift operations to convert for enianism.
// The existence of this function is assumed from the question.
extern unsigned char fun(void);
typedef struct
{
unsigned char Byte;
short WordA;
short WordB;
short WordC;
short WordD;
} converted_data;
void ConvertByteArray(converted_data* Dest, unsigned char* Source)
{
Dest->Byte = Source[0];
// The following assume that the Source bytes are MSB first.
// If they are LSB first, you will need to swap the indeces.
Dest->WordA = (((short)Source[1]) << 8) + Source[2];
Dest->WordB = (((short)Source[3]) << 8) + Source[4];
Dest->WordC = (((short)Source[5]) << 8) + Source[6];
Dest->WordD = (((hshort)Source[7]) << 8) + Source[8];
}
int main(void)
{
unsigned char array[9];
converted_data convertedData;
// Fill the array as per the question.
int i;
for ( i = 0; i< 9 ; i++)
{
array[i] = fun();
}
// Perform the conversion
ConvertByteArray(&convertedData, array);
// Note the use of %h not %d to specify a short in the printf!
printf( " 1. Byte %x a = %h , b=%h c =%h d =%h\n",
(int)convertedData.Byte, // Cast as int because %x assumes an int.
convertedData.WordA,
convertedData.WordB,
convertedData.WordC,
convertedData.WordD );
return 0;
}
Here is this simple code:
char a = '10';
char b = '6';
printf("%d\n", a | b);
printf("%d\n", a ^ b);
printf("%d\n", a << 2);
and the output is
54
6
192
Now my question is, why these results. I checked it on paper and what I have is
1110 for a | b = 14
1100 for a ^ b = 12
00101000 for a << 2 = 40
So why this different result?
You are declaring:
char a = '10';
char b = '6';
In this case b is 00110110 (0x36) because you are declaring a character, not an integer.
I also don't know why char a = '10'; even works because single quotes (') are used to create only single chars literals and you're declaring two there.
The correct way should be:
char a = 10;
char b = 6;
printf("%d\n", a | b);
printf("%d\n", a ^ b);
printf("%d\n", a << 2);
You solved this on paper for int 10 and 6 not for chars '10' = 49 or 48 (interpretation of multi-character constant is compiler dependent) and '6' = 54.
This is because you defined the variables as character(char) but in the notebook
you are calculating the result by treating them as Integer(int)
If you want the correct answer try this code and check -
int a = 10;
int b = 6;
printf("%d\n", a | b);
printf("%d\n", a ^ b);
printf("%d\n", a << 2);