Вопрос

What is the best practice for exporting a packed structure containing booleans?

I ask this because I'm trying to find the best way to do that. Current I do:

#ifndef __cplusplus
#if __STDC_VERSION__ >= 199901L
#include <stdbool.h>    //size is 1.
#else
typedef enum {false, true} bool; //sizeof(int)
#endif
#endif

now in the above, the size of a boolean can be 1 or sizeof(int)..

So in a structure like:

#pragma pack(push, 1)
typedef struct
{
    long unsigned int sock;
    const char* address;
    bool connected;
    bool blockmode;
} Sock;
#pragma pack(pop)

the alignment is different if using C compared to C99 & C++. If I export it as an integer then languages where boolean is size 1 have alignment problems and need to pad the structure.

I was wondering if it would be best to typedef a bool as a char in the case of pre-C99 but it just doesn't feel right.

Any better ideas?

Это было полезно?

Решение

It depends on what you're looking for: preserve space but run a few extra instructions, or waste a few bytes but run faster.

If you're looking to be fast, but can "waste" a few bytes of space (i.e. a single value for each boolean flag, see sizeof bool discussion), your current approach is the superior. That is because it can load and compare the boolean values directly without having to mask them out of a packed field (see next).

If you're looking to preserve space then you should look into C bitfields:

struct Sock {
    ...
    int connected:1; // For 2 flags, you could also use char here.
    int blockmode:1;
}

or roll your own "flags" and set bits in integer values:

#define SOCKFLAGS_NONE      0
#define SOCKFLAGS_CONNECTED (1<<0)
#define SOCKFLAGS_BLOCKMODE (1<<1)

struct Sock {
    ...
    int flags; // For 2 flags, you could also use char here.
}

Both examples lead to more or less the same code which masks bits and shifts values around (extra instructions) but is denser packed than simple bool values.

Другие советы

IMHO, using #pragma pack is more pain (in long term) than the gain (in short term).

  • It is compiler specific; non-standard and non-portable

  • I understand the embedded systems or protocols scenarios. With little extra effort, the code can be written pragma free.

  • I too want to pack my structure as much as possible and lay out the members in wider-first way as you did. However, I do not mind losing 2 bytes, if that allows my code to be standard-compliant and portable.

I would do the following three things:

  • Declare the flags as bool (you already did) and assign true/false
  • Put them as last members of the struct (you already did)
  • Use bitfield (as suggested by fellow stackers)

Combining these:

typedef struct Sock
{
    long unsigned int sock;
    const char* address;
    bool connected : 1;
    bool blockmode : 1;
} Sock;

In the pre-C99 case, it is risky to typedef char bool;. That will silently break code like:

bool x = (foo & 0x100);

which is supposed to set x to be true if that bit is set in foo. The enum has the same problem.

In my code I actually do typedef unsigned char bool; but then I am careful to write !! everywhere that an expression is converted to this bool. It's not ideal.

In my experience, using flags in an integral type leads to fewer issues than using bool in your structure, or bitfields, for C90.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top