Question

I'm inexperienced with C, and working on a microcontroller with messages stored in arrays where each byte does something different. How do I give each element of the array a human-readable name instead of referencing them as msg[1], msg[2], etc.?

Is this what structs are for? But "you cannot make assumptions about the binary layout of a structure, as it may have padding between fields."

Should I just use macros like this? (I know "macros are bad", but the code is already full of them)

#define MSG_ID       msg[0]
#define MSG_COMMAND  msg[1]

Oh! Or I guess I could just do

MSG_ID = 0;
MSG_COMMAND = 1;
MSG[MSG_ID];

That's probably better, if a little uglier.

Was it helpful?

Solution

If you want to go that route, use a macro, for sure, but make them better than what you suggest:

#define MSG_ID(x)      (x)[0]
#define MSG_COMMAND(x) (x)[1]

Which will allow the code to name the arrays in ways that make sense, instead of ways that work with the macro.

Otherwise, you can define constants for the indexes instead (sorry I could not come up with better names for them...):

#define IDX_MSG_ID      0
#define IDX_MSG_COMMAND 1

And macros are not bad if they are used responsibly. This kind of "simple aliasing" is one of the cases where macros help making the code easier to read and understand, provided the macros are named appropriately and well documented.

Edit: per @Lundin's comments, the best way to improve readability and safety of the code is to introduce a type and a set of functions, like so (assuming you store in char and a message is MESSAGE_SIZE long):

typedef char MESSAGE[MESSAGE_SIZE];
char get_message_id(MESSAGE msg) { return msg[0]; }
char get_message_command(MESSAGE msg) { return msg[1]; }

This method, though it brings some level of type safety and allows you to abstract the storage away from the use, also introduces call overhead, which in microcontroller world might be problematic. The compiler may alleviate some of this through inlining the functions (which you could incentize by adding the inline keyword to the definitions).

OTHER TIPS

The most natural concept for naming a set of integers in C are enumerations:

enum msg_pos { msg_id, msg_command, };

By default they start counting at 0 and increment by one. You would then access a field by msg[msg_id] for example.

It's fine to use a struct if you take the time to figure out how your compiler lays them out, and structs can very useful in embedded programming. It will always lay out the members in order, but there may be padding if you are not on an 8-bit micro. GCC has a "packed" attribute you can apply to the struct to prohibit padding, and some other compilers have a similar feature.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top