Designators in c89 - c

C99 allows array initializers (among others) to specify which element of the array is being set with a positive integer designator ($6.7.8.6, $6.7.8.17), for example like so:
const char *foo[] = {[2] = "foo", [1] = "bar", [0] = "baz"};
I have previously used this to make an enum-to-string table like so:
enum {THING_FOO = 0, THING_BAR, THING_BAZ};
const char *table[] = {
[THING_FOO] = "foo",
[THING_BAR] = "bar",
[THING_BAZ] = "baz"
}
However, I am now working under the requirement that my code is c89 compliant.
I have looked into preprocessor magic (as in here, for example) but I need the strings to be arbitrary, not copies of the enum symbols.
It isn't sufficient to just do
enum {THING_FOO = 0, THING_BAR, THING_BAZ};
const char *table[] = {"foo", "bar", "baz"};
because I will need to add enum elements in the future. Using the c99 method, this would result in NULL pointers in the table which are acceptably easy to debug if they become problems. If I forgot to update the string table using this method, I'd get segfaults which are harder to debug. Also it defeats the point of having symbols if I have to remember offsets anyway.
If the declaration were in a function, I could achieve the desired effect like this:
enum {THING_FOO = 0, THING_BAR, THING_BAZ, NUM_THINGS};
void foo(void)
{
static const char *table[NUM_THINGS];
table[THING_FOO] = "foo";
table[THING_BAR] = "bar";
table[THING_BAZ] = "baz";
/* ... */
}
However, at least with gcc, this does not get optimized.
Is there any way of declaring such a string table in c89?
(It's no problem in assembly.)

What about the simple, old fashioned
const char* table[] = { "foo", "bar", "baz" };
In other words, just put them in the correct order.
char *foo_string = table[FOO];
Of course, that only works for simple enums like the above, not for enums in the style
enum { FOO = 13; BAR = 15, BAZ = 312 };
But for that, you would have to create an array with at least 313 elements, most of which are NULL anyway, which would be a pretty wasteful construct. In such cases, the compiler can optimize this for you, when you use a switch construct.
Also take a look at the S.O. question #Leandros pointed to: How to convert enum names to string in c. The answer there uses macros to generate the array, which ensures the entries are in the correct order.
Or, as that answer says:
#define enum_str(s) #s
Which gets rid of the array altogether.

#define DEF_FOO_ENUM(E0, S0, E1, S1, E2, S2) \
enum foo { E0, E1, E2 }; \
const char *foo_str = { S0, S1, S2 };
DEF_FOO_ENUM(THING_FOO, "foo",
THING_BAR, "bar",
THING_BAZ, "baz");
The symbols and strings are paired. You're not easily going to add a new symbol without a string, or vice versa. To add an element, you have to two new arguments to the macro—E3, S3—and so on. There is nothing to keep in sync there, just that the enum has all the E-s and the array has all the S-s. This is almost impossible to screw up.

You can keep them together by using X-Macros:
#define MYXMACRO(OP) \
OP(ENUM_FOO, "foo") \
OP(ENUM_BAR, " bar") \
OP(ENUM_BAZ, "baz")
/* use the first parameter to set up your enums*/
enum {
#define AS_ENUMS(x,y) x,
MYXMACRO(AS_ENUMS)
#undef AS_ENUMS /*not required, just playing nice*/
NUMTHINGS
};
/* use the 2nd parameter to set up your strings*/
const char *strings[] = {
#define AS_STRINGS(x,y) y,
MYXMACRO(AS_STRINGS)
#undef AS_STRINGS
};
#undef MYXMACRO
Now your new data can be added as a set of enum and string. If you later decided to add something else based on the enums it's easily extended with a 'z' parameter to OP() or even ... and __VA_ARGS__ for multiple but varying number of parameters.

After trying a few different techniques, this one is easiest to maintain:
const char *table[] = {
#define FOO 0
"foo",
#define BAR (FOO + 1)
"bar",
#define BAZ (BAR + 1)
"baz"
}
Here all the information about an entry is clustered. To insert an element you only have to modify stuff right around it. For example to insert qux:
const char *table[] = {
#define FOO 0
"foo",
#define QUX (FOO + 1) /* new */
"qux", /* new */
#define BAR (QUX + 1) /* modified */
"bar",
#define BAZ (BAR + 1)
"baz"
}
It's a bit ugly (kind of endearing, you know?) but it works good.

Related

How can I write these char arrays in a nicer way?

Right now I have an array of char arrays, which I'm using to store font data:
const char * const FONT[] = {
"\x48" "a44448", //0
"\x27" "m\x48" "m\x40", //1
"\x06" "a46425" "m\x00" "m\x80", //2
"\x06" "a46425" "a42425", //3
"\x83" "m\x03" "m\x68" "m\x60", //4
"\x88" "m\x08" "m\x04" "m\x44" "a42424" "m\x00", //5
"\x02" "a42428" "a84842", //6
"\x08" "m\x88" "m\x20", //7
"\x44" "A46428" "a42428", //8
"\x86" "a46428" "m\x60", //9
...
Is there a way to write this in a more readable way, but still have it computed at compile time?
For example, something like:
#define start(x,y) //somehow create '\x<x><y>'. start(3,4) -> '\x34'
#define arc(x,y,rx,ry,a) //evaluate to {'a','<x>','<y>','<rx>','<ry>','<a>'}. arc(1,2,3,4,5) -> {'a','1','2','3','4','5'}
const char * const FONT[] = {
start(4,8) arc(4,4, 4,4, 8) "", //somehow concatenate them
...
Also, why can I use string literals but not char array literals:
(This doesn't work)
const char * const FONT[] = {
{'\x48','a','4','4','4','4','8','\0'}, //0
But this works:
const char X[] = {'\x48','a','4','4','4','4','8','\0'};
const char * const FONT[] = {
X,
...
This set of macro's should do what you want :
#define str(s) #s
#define start(px,py) str(\x##px##py)
#define arc(x,y,rx,ry,pa) str(a##x##y##rx##ry##pa)
const char * const FONT[] = {
start(4,8) arc(4,4, 4,4, 8),
}
This makes use of the # and ## operators (aka stringization resp. concatenation operators).
And results in the following pre-compiler output :
const char * const FONT[] = {
"\x48" "a44448",
}
Is there a way to write this in a more readable way, but still have it
computed at compile time? For example, something like:
#define start(x,y) //somehow create '\x<x><y>'. start(3,4) -> '\x34'
#define arc(x,y,rx,ry,a) //evaluate to {'a','<x>','<y>','<rx>','<ry>','<a>'}. arc(1,2,3,4,5) -> {'a','1','2','3','4','5'}
const char * const FONT[] = {
start(4,8) arc(4,4, 4,4, 8) "", //somehow concatenate them
...
You can implement your start() macro with use of the preprocessor's stringification (#) and token-pasting (##) operators. You need to be a little careful with these, however, to account for the fact that their arguments are not first macro-expanded. Where you do want macro expansion, you can achieve it by interposing an extra layer of macro. For example:
// Stringify the argument (without expansion)
#define STRINGIFY(x) #x
// Expand the argument and stringify the result
#define STRINGIFY_EXPANSION(x) STRINGIFY(x)
// Assumes that the arguments should not themselves be expanded
#define MAKE_HEX(x, y) \ ## x ## y
#define start(x,y) STRINGIFY_EXPANSION(MAKE_HEX(x,y))
Similarly, you can implement your arc() macro as
// No macro expansion wanted here, neither at this level nor before stringifying
#define arc(x,y,rx,ry,a) STRINGIFY(x ## y ## rx ## ry ## a)
(Technically, that creates a string literal token that implies a null terminator, not the unterminated char array you described, but that's what you really want anyway.)
Also, why can I use string literals but not char array literals: (This
doesn't work)
const char * const FONT[] = {
{'\x48','a','4','4','4','4','8','\0'}, //0
But this works:
const char X[] = {'\x48','a','4','4','4','4','8','\0'};
const char * const FONT[] = {
X,
...
Largely because those are not array literals. They are plain initializers. Initializers provide a sequence of values used to initialize an object being declared; when that object is a compound one, such as an array or struct, multiple values presented in its initializer provide initial values for some or all of its members. The members of your array FONT are of type char *, and those pointers are what an initializer provides values for. They furthermore have no deeper structure, so no nested braces are expected.
An array literal might look like this:
(const char[]) {'\x48','a','4','4','4','4','8','\0'}
And, because arrays decay to pointers in initializers, too, just as they do most everywhere else, you indeed can use array literals to initialize your array of pointers:
const char * const FONT[] = {
(const char[]) {'\x48','a','4','4','4','4','8','\0'},
// ...
};
A nicer way would be to write it all in hexadecimal notation even for printable characters. But given the different length that would still be a mess.
How about loading the font from a file at runtime or linking it in as binary blob from a file? There isn't really a good way of making binary data look good in source.
You have almost got the reason. You declare an array of pointers because you have rows of different sizes. So in const char * const FONT[] = {..., FONT is an array of const pointers to arrays of const chars. A litteral string is a const char array so it will decay to a pointer that will be used for the initialization of FONT. If you first declare a char array and use its name, things go well too, because here again the array decays to a pointer.
But in C {'\x48','a','4','4','4','4','8','\0'} is not by itself an array but only an initialization list that can only be used to initialize a character array. For example:
char arr_ok[] = { '1', '2', '3', '\0' }; // correct initialization of a char[4]
char *ptr_ko = { '1', '2', '3', '\0' }; // wrong initialization of a char* (should not compile)
That means that the initialization list is not an array and cannot decay to a pointer.
Things would be different for a 2D array:
char arr2D[][9] = { { '1', '2', '3' }, { '4', '5', '6' }, { '7', '8', '9'} };
This line initializes the 3 sub arrays with resp. '1','2','3' '4','5','6 and '7','8','9'. But it cannot be used for an array of pointers

Array of macros in C

Can I do array of macros
I am trying to define array of macros, Please check the below code and let me know can I do it like this:
#include <stdio.h> 
struct da
{
    unsigned char d1:1;
    unsigned char d2:1;
};
struct da stDataVar;
#define DATA_1 stDataVar.d1
#define DATA_2 stDataVar.d2 = 1
unisgned char arrChar[2] = {DATA_1, DATA_2};
main()
{
 
printf("data = %d\n",arrChar[0]);
}
It doesn't make any sense to have "an array of macros". In your case, the macros probably just obfuscate the code. In particular, you shouldn't hide side effects inside macros that you are using for initialization.
Is there any reason why you can't do like this?
// elsewhere in the code:
stDataVar.d2 = 1;
...
unsigned char arrChar[2] =
{
stDataVar.d1,
stDataVar.d2
};
arrChar[0] is the 1st element of arrChar[2] i.e. DATA_1 which is a macro that gets textually replaced by the preprocessor as stDataVar.d1 which is structure stDataVar(of type struct da)'s d1 bit field which is zero or garbage (depends on compiler if that initializes a character by default)

Detecting mismatched array <-> enum initializers

When doing embedded programming with C, many times I find myself doing maps with enum and array because they are fast and memory efficient.
enum {
ID_DOG = 0,
ID_SPIDER,
ID_WORM,
ID_COUNT
};
int const NumberOfEyes[ID_COUNT] = {
2,
8,
0
};
Problem is that sometimes when adding/removing items, I make mistake and enum and array go out of sync. If initializer list is too long, compiler will detect it, but not other way around.
So is there reliable and portable compile time check that initializer list matches the length of the array?
This is possibly a situation where X macros could be applied.
animals.x
X(DOG, 2)
X(SPIDER, 8)
X(WORM, 0)
foo.c
enum {
#define X(a,b) ID_##a,
#include "animals.x"
#undef X
};
int const numberOfEyes[] = {
#define X(a,b) b,
#include "animals.x"
#undef X
};
This not only guarantees that the lengths match, but also that the orders are always kept in sync.
What about a compile time assertion like the following? (Yes, there are more elaborate CT_ASSERT macros; this is to illustrate the idea.)
#define CT_ASSERT(expr, name) typedef char name[(expr)?1:-1]
enum {
ID_DOG = 0,
ID_SPIDER,
ID_WORM,
ID_COUNT
};
int const NumberOfEyes[] = {
2,
8,
0
};
CT_ASSERT (sizeof NumberOfEyes/sizeof *NumberOfEyes == ID_COUNT, foo);
Now when the NumberOfEyes array has more or less elements than ID_COUNT, this will cause an error along x.c:15: error: size of array 'foo' is negative. Negative array dimensions are a constraint violation that must be diagnosed by any C compiler out there.

Counting preprocessor macros

I have this macro code, which allows me to define both a C enum and a list of the enumerated names as strings using one construct. It prevents me from having to duplicate enumerator names (and possibly introducing errors for large lists).
#define ENUM_DEFINITIONS(F) \
F(0, Item1) \
F(5, Item2) \
F(15, Item3) \
...
F(63, ItemN)
then:
enum Items {
#define ITEM_ENUM_DEFINE(id, name) name = id,
ENUM_DEFINITIONS(ITEM_ENUM_DEFINE)
#undef ITEM_ENUM_DEFINE
which, when expanded, should produce:
enum Items {
Item1 = 0,
Item2 = 5,
Item3 = 15,
...
ItemN = 63,
}
In the implementation file, I have this code:
const char* itemNames[TOTAL_ITEMS];
int iter = 0;
#define ITEM_STRING_DEFINE(id, name) itemNames[iter++] = #name;
ENUM_DEFINITIONS(ITEM_STRING_DEFINE)
#undef ITEM_STRING_DEFINE
which, when expanded, produces:
itemNames[iter++] = "Item1";
itemNames[iter++] = "Item2";
itemNames[iter++] = "Item3";
...
itemNames[iter++] = "ItemN";
I'd like to know how many enumerator items I've created in this fashion and be able to pass it to compile-time arrays. In the example above, this would be determining that TOTAL_ITEMS = N at compile-time. Is it possible to count macro invocations in this way?
I've seen mention of a non-standard COUNTER macro, similar to the FILE and LINE macros, but I'm hoping there is a more standard way.
Would also be interested in hearing if there is a better way to achieve this without having to use macros.
The following should work:
#define ITEM_STRING_DEFINE(id, name) #name, // note trailing comma
const char *itemNames[] = {
ENUM_DEFINITIONS(ITEM_STRING_DEFINE)
};
#define TOTAL_ITEMS (sizeof itemNames / sizeof itemNames[0])
Edit: Thank you to Raymond Chen for noting we don't have to worry about the unnecessary final comma in the list. (I had been misremenbering the problem for enums with strict C89 compilers, as in Is the last comma in C enum required?.)
You can use the same technique to count the invocations.
enum itemscounter {
#define ITEM_ENUM_DEFINE(id, name) name##counter,
ENUM_DEFINITIONS(ITEM_ENUM_DEFINE)
#undef ITEM_ENUM_DEFINE
TOTAL_ITEMS
};
Would also be interested in hearing if there is a better way to achieve this without having to use macros.
You could always use a scripting language such as ruby or python to generate .c and .h files for you. If you do it well, you can integrate your script into your Makefile.
I know this isn't a complete answer.
You can create a macro around something like this.
#include <stdio.h>
const char * array[] = {
"arr1", "arr2", "arr3", "arr4"
};
int main (int argc, char **argv)$
{
printf("%d\n", sizeof(array)/sizeof(const char *));
}
If you can modify your enum so it has continous elements you can do sth like this (from Boost)
enum { A=0,B,C,D,E,F,N };
const char arr[N]; // can contain a character for each enum value
See the suggestions Mu Dynamics 'Enums, Strings and Laziness'; these are at least related to what you're after.
Otherwise, look at the Boost Preprocessor collection (which is usable with the C preprocessor as well as the C++ preprocessor).

Combine designated initializers and malloc in C99+?

Is there a nice way to combine designated initializers from C99, with the result of a malloc?
The following seems to have needless duplication:
typedef struct {
int a, b, c;
} Type;
Type *t = malloc(sizeof *t);
*t = (Type) {
.a = 2,
.b = 3,
.c = 5,
};
Can the use of Type, and *t be removed from the above code?
Since you asked ;) there is one tool in C to avoid explicit duplication of code, macros. That said I don't see a way not to repeat at least the name of the type. But in C++ they can't either, so C is at least as good :)
The easiest I see is
#define DESIGNATE_NEW(T, ...) \
memcpy(malloc(sizeof(T)), \
&(T const){ __VA_ARGS__ }, \
sizeof(T))
which would give
Type *t = DESIGNATE_NEW(Type,
.a = 2,
.b = 3,
.c = 5,
);
this has several advantages.
It initializes all members correctly, even on architectures with non
standard representations of the 0 for float types or pointers.
Other than Keith' version it is "coding style" acceptable since it is just an expression that looks like an initialization and anybody should immediately capture visually what the second code snipset is supposed to do.
NB: Observe the const in the macro, this allows several instances of the compound literal to be folded, if the compiler decides this to be relevant. Also there are means to have a variant where the list of designators is optional, see P99 below.
The disadvantage is the memcpy and I would be happier with an assignment. Second there is no check for failure of malloc before using the result, but one could probably come across with some weirdness to have the code exit nicely.
In P99 I go a slightly different way. There we always have an initialization function for a type, something like
inline
Type* Type_init(Type* t, int a, int b, int c) {
if (t) {
*t = (Type const){ .a = a, .b = b, .c = c };
}
return t;
}
which by macro magic can be made to provide default arguments for a, b and c if they are omitted. Then you can simply use something like
Type *t = P99_NEW(Type, 1, 2, 3);
in your application code. This is better, since it avoids dereferrencing the pointer when the call to malloc failed. On the other hand this reintroduces an order to the initializers, so not perfect either.
You can with a variadic macro. I'm not going to claim that this is a good idea, but it works:
#include <stdlib.h>
#include <stdio.h>
#define CREATE(type, ptr, ...) \
type *ptr = malloc(sizeof *ptr); \
if (ptr) *ptr = (type){__VA_ARGS__}
int main(void)
{
typedef struct {
int a, b, c;
} Type;
CREATE(Type, t, .a = 2, .b = 3, .c = 5);
printf("t->a = %d, t->b = %d, t->c = %d\n", t->a, t->b, t->c);
return 0;
}
Note that I wasn't able to use the usual do { ... } while (0) macro definition trick (it would create a new scope, and t wouldn't be visible), so you'd have to be careful about the context in which you use this.
Personally, I think I'm happier with the needless duplication.
No, that's the only way to use designated initializers. Without the (Type){}, the compiler doesn't know how to validate the contents.

Resources