Hi-Tech C Compiler struct of bits - c

I am using the MPLAB X IDE with Hi-Tech C Compiler on an PIC-controller.
Therefore it is important ti thing a little bit "Byte-orientated".
So I try the following:
volatile struct{
unsigned bit white:1;
unsigned bit red:1;
unsigned bit blue:1;
unsigned bit green:1;
unsigned bit violett:1;//Magenta
unsigned bit yellow:1;
}ColorPick;
Now I am not sure if it is declared correctly and What happens, when I drop some Bit-Shifting over that.
In My Result it should only be one bit aktive (1) and all other low (0).
So is "white the bit 0b00000001 or 0b10000000 ?
And when I shift it 6 times I will get yellow. And after that white again.
Can I do that in an identically funktion call of ColorPick << 1; ?
I guess the 1 get shifted to bit 7 and 8 I did not declared as such.
How can I correct this?

From the Hi-Tech C User Manual, page 346:
A.9.4 The order of allocation of bit-fields within an int (6.5.2.1)
The first bit-field defined in a structure is allocated the least
significant bit position in the storage unit. Subsequent bit-fields
are allocated higher-order bits.
Based on the documentation, I don't think that bit is a keyword in your compiler.
It has been my experience that bitfields are compiler dependent. The way I determine the bit alignments is to write a little command line program that does something like this:
union test_u {
struct test_s {
unsigned long bwhite : 1;
unsigned long bred : 1;
unsigned long bblue : 1;
unsigned long bgreen : 1;
unsigned long bviolet : 1;
unsigned long byellow : 1;
unsigned long bpink : 1;
} bits;
unsigned long unlong;
} bitest;
bitest.unlong = 0;
bitest.bred = 1;
printf("0x%8.8X\n", bitest.unlong);
Then substitute values in as needed to see where your compiler sticks them. If you need to communicate with other computers/compilers, you would probably be better off using masks and shifts yourself.

Related

shifting an unsigned char by more than 8 bits

I'm a bit troubled by this code:
typedef struct _slink{
struct _slink* next;
char type;
void* data;
}
assuming what this describes is a link in a file, where data is 4bytes long representing either an address or an integer(depending on the type of the link)
Now I'm looking at reformatting numbers in the file from little-endian to big-endian, and so what I wanna do is change the order of the bytes before writing back to the file, i.e.
for 0x01020304, I wanna convert it to 0x04030201 so when I write it back, its little endian representation is gonna look like the big endian representation of 0x01020304, I do that by multiplying the i'th byte by 2^8*(3-i), where i is between 0 and 3. Now this is one way it was implemented, and what troubles me here is that this is shifting bytes by more than 8 bits.. (L is of type _slink*)
int data = ((unsigned char*)&L->data)[0]<<24) + ((unsigned char*)&L->data)[1]<<16) +
((unsigned char*)&L->data)[2]<<8) + ((unsigned char*)&L->data)[3]<<0)
Can anyone please explain why this actually works? without having explicitly cast these bytes to integers to begin with(since they're only 1 bytes but are shifted by up to 24 bits)
Thanks in advance.
Any integer type smaller than int is promoted to type int when used in an expression.
So the shift is actually applied to an expression of type int instead of type char.
Can anyone please explain why this actually works?
The shift does not occur as an unsigned char but as a type promoted to an int1. #dbush.
Reasons why code still has issues.
32-bit int
Shifting a int 1 into the the sign's place is undefined behavior UB. See also #Eric Postpischil.
((unsigned char*)&L->data)[0]<<24) // UB
16-bit int
Shifting by the bit width or more is insufficient precision even if the type was unsigned. As int it is UB like above. Perhaps then OP would have only wanted a 2-byte endian swap?
Alternative
const uint8_t *p = &L->data;
uint32_t data = (uint32_t)p[0] << 24 | (uint32_t)p[1] << 16 | //
(uint32_t)p[2] << 8 | (uint32_t)p[3] << 0;
For the pedantic
Had int used non-2's complement, the addition of a negative value from ((unsigned char*)&L->data)[0]<<24) would have messed up the data pattern. Endian manipulations are best done using unsigned types.
from little-endian to big-endian
This code does not swap between those 2 endians. It is a big endian to native endian swap. When this code is run on a 32-bit unsigned little endian machine, it is effectively a big/little swap. On a 32-bit unsigned big endian machine, it could have been a no-op.
1 ... or posibly an unsigned on select platforms where UCHAR_MAX > INT_MAX.

C: Difference between U64 and uint64_t

I am trying to learn C after working with Java for a couple of years.
I've found some code that I wanted to reproduce which looked something like this:
U64 attack_table[...]; // ~840 KiB
struct SMagic {
U64* ptr; // pointer to attack_table for each particular square
U64 mask; // to mask relevant squares of both lines (no outer squares)
U64 magic; // magic 64-bit factor
int shift; // shift right
};
SMagic mBishopTbl[64];
SMagic mRookTbl[64];
U64 bishopAttacks(U64 occ, enumSquare sq) {
U64* aptr = mBishopTbl[sq].ptr;
occ &= mBishopTbl[sq].mask;
occ *= mBishopTbl[sq].magic;
occ >>= mBishopTbl[sq].shift;
return aptr[occ];
}
U64 rookAttacks(U64 occ, enumSquare sq) {
U64* aptr = mRookTbl[sq].ptr;
occ &= mRookTbl[sq].mask;
occ *= mRookTbl[sq].magic;
occ >>= mRookTbl[sq].shift;
return aptr[occ];
}
The code is not that important but I already failed at using the same datatype: U64, I only found uint64_t. Now I would like to know where the difference in U64, uint64_t and long is.
I am very happy if someone could briefly explain this one to me, including the advantage of each of them.
Greetings,
Finn
TL;DR - for a 64-bit exact width unsigned integer, #include <stdint.h> and use uint64_t.
Presumably, U64 is a custom typedef for 64-bit wide unsigned integer.
If you're using at least a C99 compliant compiler, it would have <stdint.h> with a typedef for 64-bit wide unsigned integer with no padding bits: uint64_t. However, it might be that the code targets a compiler that doesn't have the standard uint64_t defined. In that case, there might be some configuration header where a type is chosen for U64. Perhaps you can grep the files for typedef.*U64;
long on the other hand, is a signed type. Due to various undefined and implementation-defined aspects of signed math, you wouldn't want to use a signed type for bit-twiddling at all. Another complication is that unlike in Java, the C long doesn't have a standardized width; instead long is allowed to be only 32 bits wide - and it is so on most 32-bit platforms, and even on 64-bit Windows. If you ever need exact width types, you wouldn't use int or long. Only long long and unsigned long long are guaranteed to be at least 64 bits wide.

Is there a way to specify int size in C?

I'm trying to check some homework answers about overflow for 2's complement addition, subtraction, etc. and I'm wondering if I can specify the size of a data type. For instance if I want to see what happens when I try to assign -128 or -256 to a 7-bit unsigned int.
On further reading I see you wanted bit sizes that are not normal ones, such as 7 bit and 9 bit etc.
You can achieve this using bitfields
struct bits9
{
int x : 9;
};
Now you can use this type bits9 which has one field in it x that is only 9 bits in size.
struct bits9 myValue;
myValue.x = 123;
For an arbitrary sized value, you can use bitfields in structs. For example for a 7-bit value:
struct something {
unsigned char field:7;
unsigned char padding:1;
};
struct something value;
value.field = -128;
The smallest size you have have is char which is an 8 bit integer. You can have unsigned and signed chars. Take a look at the stdint.h header. It defines a int types for you in a platform independent way. Also there is no such thing as an 7 bit integer.
Using built in types you have things like:
char value1; // 8 bits
short value2; // 16 bits
long value3; // 32 bits
long long value4; // 64 bits
Note this is the case with Microsoft's compiler on Windows. The C standard does not specify exact widths other than "this one must be at least as big as this other one" etc.
If you only care about a specific platform you can print out the sizes of your types and use those once you have figured them out.
Alternatively you can use stdint.h which is in the C99 standard. It has types with the width in the name to make it clear
int8_t value1; // 8 bits
int16_t value2; // 16 bits
int32_t value3; // 32 bits
int64_t value4; // 64 bits

How can I define a datatype with 1 bit size in C?

I want to define a datatype for boolean true/false value in C. Is there any way to define a datatype with 1 bit size to declare for boolean?
Maybe you are looking for a bit-field:
struct bitfield
{
unsigned b0:1;
unsigned b1:1;
unsigned b2:1;
unsigned b3:1;
unsigned b4:1;
unsigned b5:1;
unsigned b6:1;
unsigned b7:1;
};
There are so many implementation-defined features to bit-fields that it is almost unbelievable, but each of the elements of the struct bitfield occupies a single bit. However, the size of the structure may be 4 bytes even though you only use 8 bits (1 byte) of it for the 8 bit-fields.
There is no other way to create a single bit of storage. Otherwise, C provides bytes as the smallest addressable unit, and a byte must have at least 8 bits (historically, there were machines with 9-bit or 10-bit bytes, but most machines these days provide 8-bit bytes only — unless perhaps you're on a DSP where the smallest addressable unit may be a 16-bit quantity).
Try this:
#define bool int
#define true 1
#define false 0
In my opinion use a variable of type int. That is what we do in C. For example:
int flag=0;
if(flag)
{
//do something
}
else
{
//do something else
}
EDIT:
You can specify the size of the fields in a structure of bits fields in bits. However the compiler will round the type to at the minimum the nearest byte so you save nothing and the fields are not addressable and the order that bits in a bit field are stored is implementation defined. Eg:
struct A {
int a : 1; // 1 bit wide
int b : 1;
int c : 2; // 2 bits
int d : 4; // 4 bits
};
Bit-fields are only allowed inside structures. And other than bit-fields, no object is allowed to be smaller than sizeof(char).
The answer is _Bool or bool.
C99 and later have a built-in type _Bool which is guaranteed to be large enough to store the values 0 and 1. It may be 1 bit or larger, and it is an integer.
They also have a library include which provides a macro bool which expands to _Bool, and macros true and false that expand to 1 and 0 respectively.
If you are using an older compiler, you will have to fake it.
[edit: thanks Jonathan]

Is it safe to compare an (uint32_t) with an hard-coded value?

I need to do bitewise operations on 32bit integers (that indeed represent chars, but whatever).
Is the following kind of code safe?
uint32_t input;
input = ...;
if(input & 0x03000000) {
output = 0x40000000;
output |= (input & 0xFC000000) >> 2;
I mean, in the "if" statement, I am doing a bitwise operation on, on the left side, a uint32_t, and on the right side... I don't know!
So do you know the type and size (by that I mean on how much bytes is it stored) of hard-coded "0x03000000" ?
Is it possible that some systems consider 0x03000000 as an int and hence code it only on 2 bytes, which would be catastrophic?
Is the following kind of code safe?
Yes, it is.
So do you know the type and size (by that I mean on how much bytes is it stored) of hard-coded "0x03000000" ?
0x03000000 is int on a system with 32-bit int and long on a system with 16-bit int.
(As uint32_t is present here I assume two's complement and CHAR_BIT of 8. Also I don't know any system with 16-bit int and 64-bit long.)
Is it possible that some systems consider 0x03000000 as an int and hence code it only on 2 bytes, which would be catastrophic?
See above on a 16-bit int system, 0x03000000 is a long and is 32-bit. An hexadecimal constant in C is the first type in which it can be represented:
int, unsigned int, long, unsigned long, long long, unsigned long long

Resources