Forcing enum field to 8 bits in standard C with bitfields - c

I saw few questions here about how to force an enum to 8 or 16 bits. The common answer was that it can be done in C++11 or higher. Unfortunately, I don't have that luxury.
So, here is what I'm thinking. I only need the enum to be 8 bits when it's in a struct whose size I want to minimize. So:
Option A:
typedef enum { A, B, C, MAX = 0xFF } my_enum;
struct my_compact_struct
{
my_enum field1 : 8; // Forcing field to be 8 bits
uint8_t something;
uint16_t something_else;
};
I think most or all optimizers should be smart enough to handle the 8 bitfield efficiently.
Option B:
Not use an enum. Use typedef and constants instead.
typedef uint8_t my_type;
static const my_type A = 0;
static const my_type B = 1;
static const my_type C = 2;
struct my_compact_struct
{
my_type field1;
uint8_t something;
uint16_t something_else;
};
Option A is currently implemented and seems to be working, but since I want to do (now and in the future) what's correct now and not just what's working, I was wondering if option B is clearly better.
Thanks,

If your specific values in an enum can fit into a smaller type than an int, then a C implementation is free to choose the underlying type of the enum to be a smaller type than an int (but the type of the enum constants in this case will be int). But there is no way you can force a C compiler to use a type smaller than an int. So with this in mind and the fact that an int is at least 16 bits, you're out of luck.
But enums in C are little more than debugging aids. Just use an uint8_t type if you compiler has it:
static const uint8_t something = /*some value*/
If not then use a char and hope that CHAR_BIT is 8.

Option B would be best. You'd be defining the type in question to be a known size, and the const values you define will also be the correct size.
While you would lose out on the implicit numbering of an enum, the explicit sizing of the field and its values makes up for it.

Step into same problem, I solved it this by using attribute((packed)). Packet align data to 4 Bytes, with packet (int)sizeof(my_compact_struct) = 4, without packet (int)sizeof(my_compact_struct) = 8
typedef enum __attribute__((packed)){
A = 0x01
B = 0x10
C = 0x255 // Max value, or any other lower than this
} my_enum;
struct my_compact_struct __attribute__((packed)){
my_enum field1 : 8; // Forcing field to be 8 bits
uint8_t something;
uint16_t something_else;
};

You can use enum or even typedef enum like a grouped #define. Do not actually define a structure member, data stream, or global variable as type enum. Rather define all storage members as fixed types like uint8_t. As if you used #define just set them to the enum literal constants. If you use any kind of lint tool, then this design style will raise some messages which you will need to tailor. Just like malformed #define if the literal value doesn't fit, then bad things can happen, and either way you need to pay attention. In a debugger or hardware simulator, the enum can provide useful display reference information. Temporary variables are an exception to how global definitions are treated. For function parameters or automatic variables, and only then, define them with the enum type. In this context int is going to be the most efficient word size as well as the standard behavior of enum. There is no error possible nor hyper-optimizing you can do.

Related

Moving to preprocessor to avoid indirection

I have an array of structure:
typedef struct s_values{
field1;
field2;
field3;
}t_values;
t_values values[5];
So, there are 5 types and each types has three fields.
To get the value for a particular type and field is got using values[type].field
I want to move away from this structure and instead use constant macros.
The goal is to have a macro
#define VALUE(type, field)
:- where type is an enum and field is just the field name
How do I go about doing that?
I was thinking something like:
#define VALUE2(type, field) type##field
#define VALUE(type, field) VALUE2(type, field)
#define type1field1 7
#define type2field2 67
....
But type is actually an enum..
Also, I am not sure if using ## beats the purpose of avoiding indirection..
Anyone has a better idea.. or help to improve the direction in which I was going?
If type is a constant value anytime you use the construct values[type].field (the only case where you can hope to replace that construct with a “constant macro”), then the compiler will access it directly. In addition, if you marked the array values as const, it will know to replace values[type].field by the value of the member field of values[type], as if you had written a constant expression. Any reasonable optimizing compiler will do this for free, you don't need to pollute the source code for this. Any reasonable C compiler should hard-code the value 67 in the code of f here, as GCC does:
typedef struct s_values{
int field1;
int field2;
int field3;
}t_values;
const t_values values[5] = {7, 67};
int f(void) {
return values[0].field2;
}
If type is not a constant value when you use values[type].field then it cannot be replaced by a “constant macro”. The mapping from type and field has to be stored somewhere, and it takes an indirection to access it where it is stored. What the compiler will do for free in this case is to add the offset corresponding to field to the address where the array value is stored, so that the address to access is computed with only one multiplication and one addition (instead of two) at run-time. Again, this is optimal.

Partial bytewise access to C enum

Setting:
I define an enum in C99:
enum MY_ENUM {TEST_ENUM_ITEM1, TEST_ENUM_ITEM2, TEST_ENUM_ITEM_MAX};
I ensure with compile time asserts that TEST_ENUM_ITEM_MAX does not exceed UINT16_MAX. I assume little endian as byte order.
I have a serialize-into-buffer function with following parameters:
PutIntoBuffer(uint8_t* src, uint32_t count);
I serialize a variable holding an value into a buffer. For this task i access the variable, holding the enum, like this:
enum MY_ENUM testVar = TEST_ENUM_ITEM;
PutIntoBuffer((uint8_t*) &testVar, sizeof(uint16_t));
Question: Is it legitimate to access the enum (which is an int) in this way? Does C standard guarantee the intended behaviour?
It is legitimate as in "it will work if int is 16 bits". It does not violate any pointer aliasing rules either, as long as you use a character type like uint8_t. (De-serializing is another story though.)
However, the code is not portable. In case int is 32 bit, the enumeration constants will turn 32 bit too, as may the enum variable itself. Then the code will turn endianess-dependent and you might end up reading garbage. Checking TEST_ENUM_ITEM_MAX against UINT16_MAX doesn't solve this.
The proper way to serialize an enum is to use a pre-generated read-only look-up table which is guaranteed to be 8 bits, like this:
#include <stdint.h>
enum MY_ENUM {TEST_ENUM_ITEM1, TEST_ENUM_ITEM2, TEST_ENUM_ITEM_MAX};
static const uint8_t MY_ENUM8 [] =
{
[TEST_ENUM_ITEM1] = TEST_ENUM_ITEM1,
[TEST_ENUM_ITEM2] = TEST_ENUM_ITEM2,
};
int main (void)
{
_Static_assert(sizeof(MY_ENUM8)==TEST_ENUM_ITEM_MAX, "Something went wrong");
}
The designated initializer syntax improves the integrity of the data, should the enum be updated during maintenance. Similarly, the static assert will ensure that the list contains the right number of items.

Should be casting used for setting a bitfield?

Let's suppose, I have a following structure:
struct my_struct {
uint32_t bf1 : 3;
uint32_t bf2 : 5;
uint32_t bf3 : 16;
uint32_t bf4 : 8;
};
and the following enum:
enum bf1_values {
Val1 = 0x0;
Val2 = 0x4;
Val3 = 0x7;
};
in addition, getter and setter functions for bf1:
uint32_t bf1_getter() {
return global_struct.bf1; // cast value to (uint32_t)?
}
void bf1_setter(enum bf1_values val) {
global_struct.bf1 = val; // cast enum to (uint32_t)?
}
Should I use the typecasting in getter and setter functions for safety?
EDIT:
The structure is supposed to be sent to HW.
EDIT2:
What I want to achieve is to be really sure that enum will be correctly written to a bitfield, and correctly read from bitfield.
No need for casting here - the assignments are already 'safe' insofar as a conforming implementation shouldn't corrupt other members. Assuming normal integer overflow semantics apply, the only problematic case is signed overflow, which may raise a signal (but I'm hard pressed to see that happening in practice if the bit field width is smaller than a full word as harware support for overflow detection will be lacking) and is otherwise implementation-defined. This caveat does not apply to your example as the target types are unsigned.
Keep in mind that bit field semantics are largely implementation-defined - even using a type other than int is actually a language extension - and it's up to you to check that the compiler does what you expect it to do on all relevant platforms.
A more portable but also less convenient approach would be to just use an uint32_t and do the bit fiddling manually. IF you don't need that protability, it should be fine as-is.

C typedef enum compilation

Does using typedef enum { VALUE_1 = 0x00, ... } typeName; have any more overhead in C (specifically, compiling using AVR-GCC for an AVR MCU) than doing typedef unsigned char typeName; and then just defining each value with #define VALUE_1 0x00?
My specific application is status codes that can be returned and checked by functions. It seems neater to me to use the typedef enum style, but I wanted to be sure that it wasn't going to add any significant overhead to the compiled application.
I would assume no, but I wasn't really sure. I tried to look for similar questions but most of them pertained to C++ and got more specific answers to C++.
An enum declaration creates an enumerated type. Such a type is compatible with (and therefore has the same size and representation as) some predefined integer type, but the compiler chooses which one.
But the enumeration constants are always of type int. (This differs from C++, where the constants are of the enumerated type.)
So typedef unsigned char ... vs. typedef enum ... will likely change the size and representation of the type, which can matter if you define objects of the type or functions that return the type, but the constants VALUE_1 et al will be of type int either way.
It's probably best to use the enum type; that way the compiler can decide what representation is best. Your alternative of specifying unsigned char will minimize storage, but depending on the platform it might actually slow down access to objects relative to, say, using something compatible with int.
Incidentally, the typedef isn't strictly necessary. If you prefer, you can use a tag:
enum typeName { Value_1 = 0x00, ... };
But then you have to refer to the type as enum typeName rather than just typeName. The advantage of typedef is that it lets you give the type a name that's just a single identifier.

Difference between uint and unsigned int?

Is there any difference between uint and unsigned int?
I'm looking in this site, but all questions refer to C# or C++.
I'd like an answer about the C language.
If it is relevant, note that I'm using GCC under Linux.
uint isn't a standard type - unsigned int is.
Some systems may define uint as a typedef.
typedef unsigned int uint;
For these systems they are same. But uint is not a standard type, so every system may not support it and thus it is not portable.
I am extending a bit answers by Erik, Teoman Soygul and taskinoor
uint is not a standard.
Hence using your own shorthand like this is discouraged:
typedef unsigned int uint;
If you look for platform specificity instead (e.g. you need to specify the number of bits your int occupy), including stdint.h:
#include <stdint.h>
will expose the following standard categories of integers:
Integer types having certain exact widths
Integer types having at least certain specified widths
Fastest integer types having at least certain specified widths
Integer types wide enough to hold pointers to objects
Integer types having greatest width
For instance,
Exact-width integer types
The typedef name int N _t designates a signed integer type with width
N, no padding bits, and a two's-complement representation. Thus,
int8_t denotes a signed integer type with a width of exactly 8 bits.
The typedef name uint N _t designates an unsigned integer type with
width N. Thus, uint24_t denotes an unsigned integer type with a width
of exactly 24 bits.
defines
int8_t
int16_t
int32_t
uint8_t
uint16_t
uint32_t
All of the answers here fail to mention the real reason for uint.
It's obviously a typedef of unsigned int, but that doesn't explain its usefulness.
The real question is,
Why would someone want to typedef a fundamental type to an abbreviated
version?
To save on typing?
No, they did it out of necessity.
Consider the C language; a language that does not have templates.
How would you go about stamping out your own vector that can hold any type?
You could do something with void pointers,
but a closer emulation of templates would have you resorting to macros.
So you would define your template vector:
#define define_vector(type) \
typedef struct vector_##type { \
impl \
};
Declare your types:
define_vector(int)
define_vector(float)
define_vector(unsigned int)
And upon generation, realize that the types ought to be a single token:
typedef struct vector_int { impl };
typedef struct vector_float { impl };
typedef struct vector_unsigned int { impl };
The unsigned int is a built in (standard) type so if you want your project to be cross-platform, always use unsigned int as it is guarantied to be supported by all compilers (hence being the standard).
The uint is a possible and proper abbreviation for unsigned int. It is better readable. But: It is not C standard. You can define and use it (as all other defines) to your own responsibiity.
But unfortunately some system headers define uint too. I have found in a sys/types.h from a currently compiler (ARM):
# ifndef _POSIX_SOURCE
//....
typedef unsigned short ushort; /* System V compatibility */
typedef unsigned int uint; /* System V compatibility */
typedef unsigned long ulong; /* System V compatibility */
# endif /*!_POSIX_SOURCE */
It seems to be a concession for familiary sources programmed as Unix System V standard. To switch off this undesired behaviour (because I want to
#define uint unsigned int
by myself, I have set firstly
#define _POSIX_SOURCE
A system's header must not define things which is not standard. But there are many things which are defined there, unfortunately.
See also on my web page https://www.vishia.org/emc/html/Base/int_pack_endian.html#truean-uint-problem-admissibleness-of-system-definitions resp. https://www.vishia.org/emc.

Resources