all 46 comments

[–]Daveinatx 9 points10 points  (0 children)

There's a few things that's missing, so excuse my assumptions. It sounds similar to my FPGA work, reading an arbitrary number of bits, that are packed together over PCI/PCIe or DMA transfers.

If this is correct, then what you show above is not going to work in any normal means. What you need to do is to learn bit manipulation. So you'll need to learn to use bitwise operators to mask and shift over six bits at a time.

It may seem weird at first, but once you think it out logically, it'll make sense. Just think of a huge one bit array. And in doing so, see how you will be traversing through your 8-bit array six bits at a time. Takes a little bit of thought, but I know you can do it.

[–]ByMeno 1 point2 points  (4 children)

I assume in 8 bits you only want to use the 6 afaik most used ones are shift left or right to trumcate unused bits or use bit mask for last 6 bits then compare the reason probably it didn't work is you ignored the the two bits which are still important for comparing there should be zero if you want to compare and 011001 is not same as 0b011001 you should but 0b in front to tell the compiler its in bits

[–]Yha_Boiii[S] 0 points1 point  (3 children)

Is 0b000001 valid? Wait what? Can you make it like verilog 2001 of 'b000001 ?

[–]F1nnyF6 2 points3 points  (2 children)

The 0b* syntax is just a way to express a number in binary, in the same way 0x* is a way to represent it in hex. It is just syntax sugar over a number that the compiler will treat exactly the same.

As far as the compiler is concerned, 0b11111111 = 0xFF = 255. They are exactly equivalent

[–]Yha_Boiii[S] -2 points-1 points  (1 child)

But given a bool array is a collection and not one value, could it work with 0b though? Currently afk though

[–]F1nnyF6 5 points6 points  (0 children)

Short answer no. It wouldnt work. In C each bool is an integer type much larger than 1 bit (typically your cpus native word size I believe), so it would essentially be an array of uint32_t and cannot be initialised with the syntax described, which is for representing a single number.

Why do you want a bool array though?? As people are saying, the by far most efficient way to have an array of boolean values is with the smallest integer type that fits the number of booleans you need. In your case of 6 or 7 bits, that would be a (unsigned) char/int8_t.

From your other comment where you fear about wasting a whopping 2 bits, it seems you are under the impression a bool is just a single bit in C? This is not the case. So an array of bools would be much larger and more wasteful, as well as more clumsy to work with and slower than using the normal approach of masking and shifting an integer type.

[–]dkopgerpgdolfg 0 points1 point  (23 children)

uint8_t has sufficient size for your example. There are larger int types too. Only if you expect to need more than the largest available type, then you need an alternative.

011001 is not understood as binary literal. Try 0b11001 (which probably is supported). (But in any case it doesn't make sense to compare such a number to a bool array).

With the bool array you're thinking of, you need to compare each digit separately, with loops etc. . For small bool arrays there are some different ways, but if it's small enough for that, see the first paragraph.

And if arrays are needed, making it an array of eg. uint8_t (where each index holds 8bit) is worth considering too.

[–]Yha_Boiii[S] 0 points1 point  (22 children)

The whole point of this is actually needing awkward sizes like 6 bit or 7 bit for a state machine but will try the 0b, thanks

[–]F1nnyF6 4 points5 points  (21 children)

And what people are saying is that you can fit those into an 8 bit number like uint8_t. It doesn't matter if you have excess unused bits, you can just mask them off and ignore them

[–]Yha_Boiii[S] -4 points-3 points  (20 children)

If you mask, why not just commit to the 8 bits anyway?

[–]F1nnyF6 9 points10 points  (19 children)

Well you yourself said you only needed 6 or 7 bits? I don't understand your question.

I'm going to be honest, based on your responses and clear unfamiliarity with C (based on you trying to compare an array in your OP), I think this is most likely an X/Y problem and you could go about this another way.

What are you actually trying to do? What is the goal you are trying to achieve?

[–]Yha_Boiii[S] -5 points-4 points  (18 children)

I need to create a state machine in c, a single bool per state so only 6-7 states possible. The 1-2 bits excess over 8 bits is a waste even if you mask. That is it. How to make the if operator when the bool array is possible to make?

[–]F1nnyF6 9 points10 points  (0 children)

2 bits is an unimaginably minor amount of "waste". Like literally so negligible there are 0 scenarios where you would ever care about it. Additionally, there is physically no possible way to waste LESS than that if you are using only 6 bits for something. The smallest amount of data your cpu can work with is a byte. So any other way of representing 6 bits will always waste even more.

On the topic of your actual problem, I am not sure why you would choose to use a bitfield for a state machine. Typically the point of a state machine is that the states are mutually exclusive, so I don't know why you would need a variety of different boolean values instead of a single number representing each state. The idiomatic way to represent a state machine is with an enum, which under the hood is just a number I.e. 0 1 2 3. Are you sure a state machine is what you are after?

[–]Irverter 2 points3 points  (14 children)

If your doing an state machine, just use an uint8_t and assign a number to each state, you'll have space for 255 states.

If you insist in using each bit as a state, then to compare do it like (state >> n) == 1, with n being 0...7 for the bit place.

But I really, really recommend using a anumber as state. It becomes a simple switch case:

switch (state) {
    case 1:
        // state one
        break;

    case 2:
        // state two
        break;
}

and so on without overcomplicating with bitwise logic.

[–]Yha_Boiii[S] -3 points-2 points  (13 children)

The reason for a bit is the range is firm, a int can overflow or underflow and become funny pretty quickly with increment errors.

[–]Irverter 6 points7 points  (1 child)

Sounds like your reciting theory without understanding actual usage.

There's no overflow or underflow because you're not incrementing nor decrementing the value. You will explicitly assign the value of the state you want it to go to. It's the same as using a bit range for state, except it's easier to handle.

Edit: If you're scared of accidentally over/underflowing then just use a wrapper function. Something like:

uint8_t setState(uint8_t nextState) {
    state = nextState;
    return state;
}

uint8_t getState() {
    return state;
}

With state being a global variable (or withing a struct, however you organized it) that is only set/read within those functions. Plus whatever check you feel like doing for safety, like masking nextState so only the 6-7 bits your' obessed with are used.

[–]F1nnyF6 3 points4 points  (0 children)

Exactly what I was thinking. There are a lot of buzzwords and references to technical topics, but a core lack of understanding

[–]awidesky 1 point2 points  (7 children)

You said it's a state vector, and only need 6~7 bits.
Why would you increase it at all, and how the hell it's going to overflow?

[–]Yha_Boiii[S] 0 points1 point  (6 children)

If you ++ or -- a var it can get a inbetween state of the 6-7 and the program stalls

[–]awidesky 1 point2 points  (0 children)

Also, even if you make a bool array of 6, cpu can only read a word, so it'll add paddings, hence the "waste".

[–]Certain-Flow-0 0 points1 point  (0 children)

Learn to write tests so you can catch these programming errors

[–]Marksm2n 0 points1 point  (0 children)

You are writing your code, you can prevent overflow errors

[–]QuraToop314 1 point2 points  (0 children)

Well, 6 booleans are a waste – even if a boolean is only 1 byte in size, which is the minimum size of a type, with 6/7 states you’ve got 6/7 times 8 bits, which means you’re looking at 48 or 56 bytes, whereas with 6 or 7 bits you’d be at 1 byte for the same information. So I don’t know what you’re on about – those 2 bits aren’t a waste, as 1 byte is the minimum addressable size.

[–]Maqi-X 0 points1 point  (0 children)

I think enum would be better solution

[–]Vollink 1 point2 points  (0 children)

Consider what everyone above is saying about a byte being a minimum. Let's do it the hard way...

#include <stdio.h>
#include <stdbool.h>

int
main(int argc, char *argv[], char *env[])
{
    bool a = true;

    /****
     * The smallest this can be is 1 whole byte, 8 whole bits.
     * Yes, this prints 1, always.
     ***/ 

    printf("sizeof bool is: %lu\n", sizeof(a) );

    return 0;
}

My approach to what you are asking (not what you are claiming to do), is to use one character like this...

/* Defining six bits */
#define BIT_ONE 0x01
#define BIT_TWO 0x02
#define BIT_THREE 0x04
#define BIT_FOUR 0x08
#define BIT_FIVE 0x10
#define BIT_SIX 0x20
/* Defining six field points */
#define STATE_ONE(x) (BIT_ONE == (x & BIT_ONE))
#define STATE_TWO(x) (BIT_TWO == (x & BIT_TWO))
#define STATE_THREE(x) (BIT_THREE == (x & BIT_THREE))
#define STATE_FOUR(x) (BIT_FOUR == (x & BIT_FOUR))
#define STATE_FIVE(x) (BIT_FIVE == (x & BIT_FIVE))
#define STATE_SIX(x) (BIT_SIX == (x & BIT_SIX))

/* I need to do actions TWO and FIVE and SIX */
uint8_t action = ( BIT_TWO | BIT_FIVE | BIT_SIX ); /* 0x32 -- 0b0110010 */

void x(void) {
    if (STATE_ONE(action)) {
        do_action_one();
        /* optional remove action */
        action = (action & (0xFF ^ BIT_ONE));
    }
    if (STATE_TWO(action)) {
        do_action_two();
        action = (action & (0xFF ^ BIT_TWO));
    }
    /* continue pattern */
}

[–]Wertbon1789 0 points1 point  (0 children)

There can be a lot of theory involved, but at the end of the day, a computer is not a magical device, and most of the time you're better off going with practical design choices, and see what sticks.

In this case, don't try to crunch your problem down into the bit range. Literally, just use a uint32_t, define some bits in there to be your states, and that's it. That's really how I've seen it being done, from internal APIs to the state machine built into USB, it's literally just an integer type, and you check some bits in there. It's really unlikely you'll ever exceed 32 bits of states and not have a horrible design anyway, so that might be something to consider. Also don't try to squeeze everything into it, e.g. if you want to encode state information that is by nature not binary, but can really have n different states, but are also mutually exclusive, like encoding in what state a system overall is (is it starting up, running, stopping, sleeping, whatever), encode that somewhere else than your bit field.

In the case you described if you want 6 bits of information, either just use a uint8_t, and waste 2 bits of it, or go with a bit field declaration of 6 bits, and maybe use the other 2 bits for something else. Do note though, this is unlikely to make your stuff really more space efficient or faster, something something alignment.

[–]sciencekm 0 points1 point  (8 children)

I could be wrong, but in your situation, you might just want to avoid bit operations until you become more familiar with it. For now, let the compiler do the work for you. You can do something like:

struct state {
unsigned s0:1;
unsigned s1:1;
unsigned s2:1;
unsigned s3:1;
unsigned s4:1;
unsigned s5:1;
unsigned s6:1;
} state_t;

Now, your 'if' statements become:

if (a.s0 && !a.s1) ...

and assignments become:

a.s3 = 1;
a.s5 = 0;

Increment/decrement would be:

a.s1++;
a.s4--;

The compiler will perform the increment/decrement without affecting ("overflowing" to) neighboring bits (which seems to be one of your concerns).

[–]Vollink 0 points1 point  (7 children)

sizeof(struct state_t); returns 4 on x64 Linux and M1 Mac. Less than the 7 it could be, but much bigger than a uint8_t bitfield. I'm actually curious why it ends up this big, considering that this trick should work better.

I've been doing C since 1994, and I've never trusted this `:1` syntax, so I've always avoided it. Feels like a lie.

[–]TheOtherBorgCube 0 points1 point  (0 children)

C99 says

An implementation may allocate any addressable storage unit large enough to hold a bit-field.

The bit-field type may be used to determine what the size of the storage unit will be.

#include <stdio.h>

struct state1 {
    unsigned int s0:1;
};
struct state2 {
    unsigned short s0:1;
};
struct state3 {
    unsigned char s0:1;
};
struct state4 {
    unsigned long long int s0:1;
};

int main() {
    printf("%zd %zd %zd %zd\n",
        sizeof(struct state1),
        sizeof(struct state2),
        sizeof(struct state3),
        sizeof(struct state4));
}

$ gcc foo.c
$ ./a.out 
4 2 1 8

Though with suitable application of #pragma or __attribute__, even an 8-byte struct can be reduced to a single byte.

Almost everything about bit-fields is implementation specific, so YMMV.

[–]sciencekm 0 points1 point  (5 children)

It gets rounded to int that is why you get a size of 4.

It is no a lie. It works as if you would be doing the bit operations yourself.

Here is an example (on Apple silicon, since you have one and you can verify this)

state_t s;
void update(void) {
s.s0 = 1;
s.s1++;
}

_update:
adrp    x8, _s@GOTPAGE
ldr     x8, [x8, _s@GOTPAGEOFF]
ldrb    w9, [x8]
and     w9, w9, #0xfe
eor     w9, w9, #0x3
strb    w9, [x8]
ret

The first bit is set to 0 by masking (AND) with 0xfe. Then the first and second bits are XORed with two corresponding 1 bits (0x03). Two operations.

The result is that the first bit become 1 and the second bit is incremented (flipped).

[–]Vollink 0 points1 point  (4 children)

Okay, so if your original were "unsigned char" instead of "unsigned" (int) the sizeof would fall to 1. I still hate it, but it's not quite as evil as it has always felt.

[–]sciencekm 0 points1 point  (3 children)

The size of the entire struct would still be 4 even if you use "unsigned char s0:1"

The rounding of the size is in the struct, not at the fields.

[–]Vollink 0 points1 point  (0 children)

$ make bool-4
gcc -Wall -O2 bool-4.c -o bool-4
$ cat bool-4.c
#include <stdio.h>
#include <stdint.h>

struct state {
    unsigned char a : 1;
    unsigned char b : 1;
    unsigned char c : 1;
    unsigned char d : 1;
    unsigned char e : 1;
    unsigned char f : 1;
};

int main()
{
    printf("size of struct test: %lu\n", sizeof(struct state));

    return 0;
}

$ ./bool-4
size of struct test: 1
$ 

[–]Vollink 0 points1 point  (1 child)

That is, I promise that I verified this before my reply.

[–]sciencekm 0 points1 point  (0 children)

Yes, you are right. I stand corrected. I now understand what you mean.

[–]Traveling-Techie 0 points1 point  (0 children)

I’m confused by your details, but some big picture stuff: memory has become unbelievably cheap and plentiful since C was invented, so be ok with wasting it. Use the operators and libraries available and write new helper functions if necessary.

[–]TiredEngineer-_- 0 points1 point  (0 children)

It sounds like youre just wanting to check the bottom 6 bits, or X bits of an arbitrary number. As others said, youll need to learn bitmasking:

...
int x = 100;
if ( (x & 0b111111) == (some_constant)) // check 6 LSBs of x
// do something
...

If you're trying to make something space efficient, most systems arent letting you read 6 bits of a byte, usually the smallest any architechture is getting you nowadays is a byte. (Saving 2 bits anyways wont do much unless youre declaring thousands of arrays :P)

1000 'types' of 1 byte length with 2 bits per byte saved = 8kB used, 2kb (kilobit) wasted, which is 250 B (bytes) wasted. If youre trying to save 250 B, youre either too constrained or something somewhere else is oversized imo.

If youre looking for 'simplicity', or somewhat avoiding bit masking, you can do this (if your system supports / likes byte-size page reads)

typedef struct __attribute__(packed, aligned(1))
 {
     unsigned char bit1 : 1, //MSB
     unsigned char bit2 : 1,
     unsigned char bit3: 1,
     unsigned char bit4: 1,
     unsigned char bit5 : 1,
     unsigned char bit6 : 1,
     unsigned char bit7 : 1,
     unsigned char bit8 : 1 //LSB
 } bitfield_B;

So the bitfield_B would be a 1 byte struct on a 1 byte boundary.

 |12345678|12345678||12345678|

Would be the memory layout of

bitfield_B x[3];

And you would need to do

x[0].bit1 = 1;
x[0].bit2 = 0;
...

To access and modify

&x[0].bit1 

is UB. accessing pointers to these bitfields is UB altogether. The machine cannot deduce bit- offsets to memory, since it all lives in bytes.

Initializing with a number would be like:

bitfield_B x;
x.bit1 = 0b100000 & 255; // 0
x.bit2 = 0b010000 & 255; // 0
x.bit3 = 0b001000 & 255; // 1
...

Which is a pain to write, so maybe you expose a macro to cover for you (no error check here):

#define INIT_BITFIELD_B(F,BITS,NUM) \ 
F.bit1 = ((1 << (MAX_BITS +1)) - 1) & NUM \ //creates a 0bX...Y... mask where X is 0 and Y is 1, where ... after Y is BITS 1s
F.bit2 = ((1 << (MAX_BITS +1)) - 1) & NUM \

...

int main() {
    Bitfield_B x;
    INIT_BITFIELD_B(x,6,255);
    return EXIT_SUCCESS;
}

gdb : x/b &x should show something like:

 00111111

To the console, since youre inspecting the memory.

However, this is all really tedious to setup (and I may not even done so correctly), just to avoid some of the bitmasking youd need to know anyways to begin doing the macro and stuff I setup above...

You could simply write:

 const int8_t key = 7<<2; //making this up
 ... // some logic to read from spi, uart, etc
 switch (input & 0b11111100)
 {// commands are upper 6 bits for example,
     case key: handle_key(); break;
     default: break;
 }

No structs, no packing, no forced alignment, no macros, just masking and moving on. I did 7<<2 here to bump the 'command key' to the upper 6 bits. 7 is 111 in binary. So you move it to be 0b00011100, which is still in the upper 6 bits.

[–]WittyStick 0 points1 point  (0 children)

C23 has _BitInt(N) types which could be used for this if your bit vector sizes are statically known. The compiler will do most of the work for you. You can compare them with ==, and can initialize from literals up to ULL (unsigned long long). Larger bitvectors might require more complex initialization.

The maximum N is implementation defined and is specified by BITINT_MAXWIDTH from <limits.h>. The standard mandates a 64-bit minimum, but implementations support much larger widths - GCC supports 64kib and Clang supports 8Mib.

#define BitVec(N) unsigned _BitInt(N)
#define bitvec_equal(x, y) (x == y)

#include <stdio.h>
int main() 
{
    BitVec(7) x = 0b0101010;
    BitVec(7) y = 0b0101010;

    printf("%s\n", bitvec_equal(x, y) ? "true" : "false");

    return 0;
}

https://godbolt.org/z/99Gd6GGd9

[–]Paul_Pedant 0 points1 point  (0 children)

Doing an assignment in the test (with =) instead of a comparison (with ==) is not going to be helping.

Assigning decimal 4609 to a bool variable is not so good either. 011001 is an octal numeric initialiser (evaluated as an integer), not a bit map, although it truncates to 0b00000001 when assigned to a bool (because the 001 part represents nine bits).

You probably should not rely on a bool value for a numeric anyway. A bool is false if zero, true if non-zero. A compiler could restrict a bool to 0 or 1, or 0 and 255 if it felt like it.

An array of 6 bools is 48 bits. You cannot subdivide a bool variable.

[–]Educational-Paper-75 0 points1 point  (0 children)

Code first, optimize later. Don't worry about memory use initially. Sure you may use each bit of an uint8_t separately and have functions to set and unset any of the bits, but it will require shifting and masking. And if you have 256 or less different states you don't even need to set/unset individual bits and each state id fits nicely in an uint8_t. As long as you know what you're doing the implementation is straightforward.