accessing bit fields in structure - c

I am new to the bit fields concept. I am trying to access the elements in the structure, but it is showing the error at aa=v like this.
error: incompatible types when assigning to type ‘cc’ from type ‘long unsigned int ’
And it is showing error if I typecasted at aa= (cc)v;
error: conversion to non-scalar type requested
I tried accessing the elements by declaring a pointer to a structure. I did well in this case, but in this case I do not declare a pointer to a structure and I have to access the elements. How can I overcome this error.
Thanks for any help in advance
#include<stdio.h>
typedef struct
{
unsigned long a:8;
unsigned long b:8;
unsigned long c:8;
unsigned long d:8;
}cc;
int main()
{
cc aa ;
unsigned long v = 1458;
printf("%d\n",sizeof(aa));
aa=v; // aa= (cc)v;
printf("%d %d %d %d\n", aa.a,aa.b,aa.c,aa.d);
return 0;
}

If you intend to access the same data as multiple data-types, then you need to use an union in C. Take a look at the following snippet that will
Write to a union treating it as a 32bit integer
(and then)
Access the data back as 4 individual 8bit bit-fields
(and also for good measure)
Access the same data back again as a 32bit integer
#include<stdio.h>
typedef struct {
unsigned long a:8;
unsigned long b:8;
unsigned long c:8;
unsigned long d:8;
}bitfields;
union data{
unsigned long i;
bitfields bf;
};
int main()
{
union data x;
unsigned long v = 0xaabbccdd;
printf("sizeof x is %dbytes\n",sizeof(x));
/* write to the union treating it as a single integer */
x.i = v;
/* read from the union treating it as a bitfields structure */
printf("%x %x %x %x\n", x.bf.a, x.bf.b, x.bf.c, x.bf.d);
/* read from the union treating it as an integer */
printf("0x%x\n", x.i);
return 0;
}
Note that when union is accessed as an integer, the endian-ness of the system determines the order of the individual bit-fields. Hence the above program on a 32bit x86 PC (little-endian) will output :
sizeof x is 4bytes
dd cc bb aa
0xaabbccdd

It's because aa is a structure and v is not, the types are incompatible just like the error message says. Even if cc is a structure of bitfields, it still can only be used as a structure, with separate members, and not like an integer.

Correct me if I'm wrong, but you wanted to assign a 4 byte sized long to your 4 byte sized struct. If yes, this might be for you:
aa = *(cc*)&v;
However you should be aware about endianness in this case

Use this :
aa.a = v;
Instead of
aa = v;

you are trying to assign a long to a struct which are incompatible.
you can assign inner value of cc to v:
cc c;
unsigned long v = 1458;
c.b = v;
if you want the first 8 bits to be in a for example you can do
cc c;
unsigned long v = 1458;
c.a = v % 255;
c.b = v / 255 % 65280;

Related

Union of structs with only bit fields, sizeof function doubling bytes, C

For some reason that i cant quite figure out my union of just structs containing bit fields is setting up twice as many bytes as is are necessary for any single struct.
#include <stdio.h>
#include <stdlib.h>
union instructionSet {
struct Brane{
unsigned int opcode: 4;
unsigned int address: 12;
} brane;
struct Cmp{
unsigned int opcode: 4;
unsigned int blank: 1;
unsigned int rsvd: 3;
unsigned char letter: 8;
} cmp;
struct {
unsigned int rsvd: 16;
} reserved;
};
int main() {
union instructionSet IR;// = (union instructionSet*)calloc(1, 2);
printf("size of union %ld\n", sizeof(union instructionSet));
printf("size of reserved %ld\n", sizeof(IR.reserved));
printf("size of brane %ld\n", sizeof(IR.brane));
printf("size of brane %ld\n", sizeof(IR.cmp));
return 0;
}
All of the calls to sizeof return 4 however to my knowledge they should be returning 2.
There are a couple of problems here, first of all, your bitfield Brane is using unsigned int which is 4 byte.
Even if you just use half of the bits, you still use a full 32-bit width unsigned int.
Second, your Cmp bitfields uses two different field types, so you use 8-bit of the 32-bit unsigned int for your first 3 fields, and then you use a unsigned char for it's full 8-bit.
Because of data alignement rules, this structure would be at least 6 bytes, but potentially more.
If you wanted to optimize the size of your union to only take 16-bit. Your first need to use unsigned short and then you need to always use the same field type to keep everything in the same space.
Something like this would fully optimize your union:
union instructionSet {
struct Brane{
unsigned short opcode: 4;
unsigned short address: 12;
} brane;
struct Cmp{
unsigned short opcode: 4;
unsigned short blank: 1;
unsigned short rsvd: 3;
unsigned short letter: 8;
} cmp;
struct {
unsigned short rsvd: 16;
} reserved;
};
This would give you a size of 2 all around.
C 2018 6.7.2.1 11 allows the C implementation to choose the size of the container is uses for bit-fields:
An implementation may allocate any addressable storage unit large enough to hold a bit-field. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined.…
The implementation you are using apparently chooses to use four-byte units. Likely that is also the size of an int in the implementation, suggesting that it is a convenient size for the implementation.
It isn't specified what this code will do and it isn't meaningful to reason about it without a specific system and compiler in mind. Bit-fields are simply too poorly specified in the standard to be reliably used for things like memory layouts.
union instructionSet {
/* any number of padding bits may be inserted here */
/* we don't know if what will follow is MSB or LSB */
struct Brane{
unsigned int opcode: 4;
unsigned int address: 12;
} brane;
struct Cmp{
unsigned int opcode: 4;
unsigned int blank: 1;
unsigned int rsvd: 3;
/* anything can happen here, "letter" can merge with the previous
storage unit or get placed in a new storage unit */
unsigned char letter: 8; // unsigned char does not need to be supported
} cmp;
struct {
unsigned int rsvd: 16;
} reserved;
/* any number of padding bits may be inserted here */
};
The standard lets the compiler pick a "storage unit" for any bit-field type, which can be of any size. The standard simply states:
An implementation may allocate any addressable storage unit large enough to hold a bitfield.
Things we can't know:
How large the bitfields of type unsigned int are. 32 bits might make sense but no guarantee.
If unsigned char is allowed for bit-fields.
How large the bitfields of type unsigned char are. Could be any size from 8 to 32.
What will happen if the compiler picked a smaller storage unit than the expected 32 bits, and the bits doesn't fit inside it.
What happens if an unsigned int bit-field meets an unsigned char bit-field.
If there will be padding in the end of the union or in the beginning (alignment).
How individual storage units within the structs are aligned.
The location of the MSB.
Things we can know:
We have created some sort of binary blob in memory.
The first byte of the blob resides on the least significant address in memory. It may contain data or padding.
Further knowledge can be obtained by having a very specific system and compiler in mind.
Instead of the bit-fields we can use 100% portable and deterministic bitwise operations, that yield the same machine code anyway.
Read about memory structure padding / memory alignment. By default 32bit processor read from memory by 32bit (4bytes) because is faster. So in memory char + uint32 will be write on 4 + 4 = 8 bytes (1byte - char, 3bytes space, 4bytes uint32).
Add those lines on begin and end of your program and will be result 2.
#pragma pack(1)
#pragma unpack
This is way to say to the compiler: align memory to 1 byte (by default 4 on 32bit processor).
PS: try this example with different #pragma pack set:
struct s1
{
char a;
char b;
int c;
};
struct s2
{
char b;
int c;
char a;
};
int main() {
printf("size of s1 %ld\n", sizeof(struct s1));
printf("size of s2 %ld\n", sizeof(struct s2));
return 0;
}

Casting a float for int and int to float

Having a little difficulty with pointers. I have to store a float in an array of unsigned ints and be able to pull it out.
I know there is a special way to cast this so I don't reorder the bits, I think this is the correct way to store it when I want to put it into the array:
float f = 5.0;
int newF = (int *) f;
arrayOfInts[0] = *newF
Which seems to successfully store the value in the array.
However, at some point I have to pull the value back out of the array of ints, this is where my confusion comes in (assuming I inputed into the array correctly)
float * f = (float *) arrayOfInts[0]
int result = *f;
however, that gives me the warning: 'cast to pointer from integer of different size'
I can't really think of how to solve that without some sort of long cast.. which doesn't seem right..
I don't want to lose the value or damage the bits.. obviously It will lose decimal point precision.. but I know theirs some way to safety convert back and forth
I have to store a float in an array of unsigned ints and be able to pull it out.
Use a union and unsigned char[]. unsigned char is specified to not have any padding and all bit combinations are valid. This is not always true of many other number types. By overlaying the float with unsigned char[], code can examine each "byte" of the float, one at a time.
union {
float f;
unsigned char uc[sizeof (float)];
} x;
// example usage
x.f = 1.234f;
for (unsigned i = 0; i<sizeof x.uc; i++) {
printf("%u:%u\n", i, 1u*x.uc[i]);
}
Sample output: Yours may vary
0:182
1:243
2:157
3:63
float --> unsigned char[] --> float is always safe.
unsigned char[] --> float --> unsigned char[] is not always safe as a combination of unsigned char[] may not have a valid float value.
Avoid pointer tricks and casting. There are alignment and size issues.
// Poor code
float f = 5.0f;
int newF = *((int *) &f); // Conversion of `float*` to `int*` is not well specified.
Code can also overlay with fixed-width no-padding types like (u)int32_t if they exist (they usually do) and match in size.
#include <stdint.h>
union {
float f;
uint32_t u32;
} x32;
#include <assert.h>
#include <inttypes.h>
// example usage
assert(sizeof x32.f == sizeof x32.u32);
x32.f = 1.234f;
printf("%" PRNu32 "\n", x32.u32);
}
Example output: yours may vary
1067316150
To convert a float to an int
float fval = 123.4f;
int ival = *(int*)&fval;
To convert back
int ival = /* from float */
float fval = *(float*) &ival;
it won't work if float and int are different sizes, but presumably you know that already. The unsigned char union method outlined in other answer for chux is more robust, but over-complicated for what you probably want to do.

C, Creating a 32 bit pointer to a 8 bit array

I have a buffer where each entry in the buffer is 8 bits in size:
uint8_t Buffer[10] = {0x12,0x34,0x56,0x78,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6};
What I need to do is to create pointers to that array, for example 16 bit and 32 bit pointers. For example:
uint32_t *x;
x = Buffer;
uint32_t *y;
y = Buffer+4;
uint16_t *z;
z = Buffer+8;
Where each variable would then read from the array, for example:
x = 0x78563412
y = 0xf4f3f2f1
z = 0xf6f5
This works completely fine, the problem is that I'm getting warnings about incompatible pointer types. So I was wondering if there is an alternative way of doing this or if I'll just have to live with the warnings? Or am I simply doing this completely the wrong way?
Please note that this code will be executed on a single type of platform where the endianness is always the same and the size of data types is always the same.
You should heed the warnings; what you're doing is undefined behavior. Type aliasing like that is undefined behavior, particularly since there is no guarantee that Buffer has the correct alignment such that it can be accessed as an int/short. If Buffer has the correct alignment, then you can just explicitly cast and it's okay (and the warning will go away).
You have two options:
One, you align the buffer as the larger of the two types. Be careful that your pointer arithmetic doesn't throw off the alignment:
#include <stdalign.h>
alignas(int) unsigned char Buffer[10] = {0x12,0x34,0x56,0x78,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6};
unsigned int *x;
x = (unsigned int*)(Buffer);
unsigned int *y;
y = (unsigned int*)(Buffer+4);
unsigned short *z;
z = (unsigned short*)(Buffer+8);
Two, you create an unsigned int/unsigned short variable and then memcpy the bytes you're interested in into the variable:
unsigned int x;
memcpy(&x, Buffer, 4);
unsigned int y;
memcpy(&y, Buffer + 4, 4);
unsigned short z;
memcpy(&z, Buffer + 8, 2);
The problem with your approach is that it assumes a particular endianness of underlying hardware. Different computers will interpret a sequence of hex bytes
01 23 45 67
as eiter
01234567 or 67452301
Your program may compile and run on both systems, but since the result is hardware-specific, the compiler must warn you of the possibility.
The proper way of forcing a particular endianness is by using an array of integers, convert them using hton and ntoh functions, and set individual bytes either directly by casting a pointer to unsigned char*, or with memcpy.
You might want to use a union
#include <stdint.h>
#include <stdio.h>
typedef union{
uint8_t Buffer[10];
struct{
uint32_t x;
uint32_t y;
uint16_t z;
};
}MYSTRUCT;
int main(){
MYSTRUCT b = {0x12,0x34,0x56,0x78,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6};
printf("x=%#x y=%#x z=%#x\n",b.x,b.y,b.z);
return 0;
}

Most efficient way to subtract arrays of unsigned chars in C

I'm using libpcap to analyze and process packets. I have to compare two arrays of unsigned chars, take the difference and save it to a hashtable. Another thread will periodically scans across the hashtable and compute for average,standard deviation, max and min.
My question is the following, what would be the most efficient way to perform subtraction on two arrays?
For example:
A="0x34 0x44 0x59 0x5B"
B="0x34 0x42 0x43 0x43"
My first thought is to convert it to an integer, by converting the array into an array of signed chars, doing take requires a function to perform lookup function. Because this is function is called for every packet received on the system.
use the union can make this simple, because different data types share the same memory, we can then use this feature to convert data type.
note the Little-endian
#include <stdio.h>
typedef union new_array{
struct array {
unsigned char f4;
unsigned char f3;
unsigned char f2;
unsigned char f1;
}array;
unsigned int int_array;
}new_array;
int main()
{
new_array A, B;
A.array.f1 = 0x34;
A.array.f2 = 0x44;
A.array.f3 = 0x59;
A.array.f4 = 0x5B;
B.array.f1 = 0x34;
B.array.f2 = 0x42;
B.array.f3 = 0x43;
B.array.f4 = 0x43;
printf("%u\n", A.int_array - B.int_array);
}

Sizeof next byte in byte array

I have an unsigned char and I add integers to it but I want to get the sizeof next byte (i.e sizeof unsigned short int or unsigned int and so on).
The following code demonstrates what I want:
#include <stdio.h>
static void write_ushort(unsigned char *b, unsigned short int value) { b[1] = value >> 8; b[0] = value; }
static void write_ulong(unsigned char *b, unsigned long int value) { write_ushort(b + 2, value >> 16); write_ushort(b, value); }
static unsigned short int read_ushort(const unsigned char *b) { return b[1] << 8 | b[0]; }
static unsigned long int read_ulong(const unsigned char *b) { return read_ushort(b + 2) <<16 | read_ushort(b); }
int main() {
unsigned char b[2];
unsigned int v0; /* 4 */
unsigned short int v1; /* 2 */
v0 = 200; v1 = 1235;
write_ushort(&b[0], v0); write_ulong(&b[1], v1);
/* what i expect printf to output is:
* 4 2
* but it obviously outputs 1 1 */
printf("%d %d\n", read_ushort(&b[0]), read_ulong(&b[1]));
printf("%d %d\n", (int)sizeof(b[0]), (int)sizeof(b[1]));
return 0;
}
This isn't possible. The sizeof operator will return the size of a type, or the size of the declared type of a variable. You can't massage anything else out of it, and your code won't keep track of what type of variable a number was stored in before you assigned it to a new variable.
Regardless of the type of v0 or v1, when they're stored in elements of your array, they are converted to unsigned char.
If you want 4 2 as output, you'll need to pass sizeof(v0) and sizeof(v1) to printf, or keep track of this some other way.
C is statically typed, and you can't just change the data type of a variable (or array) by assigning something to it. In fact you can't change the data type of a variable at all: a variable corresponds (almost exactly) to a certain chunk of memory with its size defined at compile time. You can cast variables so that they are treated as though they were a different type for a specific operation, but the chunk of memory is the same size always.
And, since a variable is just a block of memory there is no way for the computer (or compiler) to know that you are using a char[2] array to store a short or a long. You have to keep track of this yourself.
Here is a major problem:
write_ulong(&b[1], v1);
You take the second byte (of a two-byte array) and pass it to write_ulong where it's handled as an array of four bytes. This means you are writing several bytes beyond the original array b and overwrite the stack. This is undefined behavior and will make your program behave very strange.

Resources