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)
Related
I was wondering if it would be a good idea to use structs as pseudo namespaces (à la C++) to group constants which are functionally or conceptually related to each other.
static const struct {
const unsigned int START;
const unsigned int END;
} COUNTER = {.START = 1, .END = 100};
Is there any downside to this? If not, is it redundant (or maybe even unconvenient) to have both the struct instance and its members declared as const? Where should the constantness of these values be stated?
I was wondering if it would be a good idea to use structs as pseudo namespaces
Well, it CAN be a good idea. It's not intrinsically bad. An argument against is that if you feel that you need namespaces, then it's likely that C is the wrong language in the first place. But it can be used this way, and it is sometimes used this way.
Where should the constantness of these values be stated?
It's in general enough to declare the whole struct as const. But beware with pointers. This code is valid and will print "42":
int x = 5;
const struct {
int *p;
} S = {.p = &x };
int main()
{
*(S.p) = 42;
printf("%d\n", x);
}
In the above code, you are not allowed to change S.p so that it points to something else, but there is a difference between a const pointer and a pointer to const. So for pointer, it could be a good idea to add an extra const.
To clarify, the pointer p will be declared like it was a int * const p which means you cannot change the pointer itself, but in order to protect the data it's pointing to, you need const int *p. To get both, use const int * const p, but if the struct is declared as const, you'll get one of them "for free" so const int *p is enough to get both.
And if you consider pointers to pointers, well, think it through for a long time and test it to make sure it works the way you want.
From comments:
Why not enums?
Because this is not valid:
enum S {a = 5};
enum Y {a = 6};
The compiler will tell you that a is already defined. So enums is not good for emulating namespaces. Also, you cannot use enums for non-integers.
Is it a good practice to group related constants using structs in C?
It's opinion based. If it works for you, do it.
I wouldn't do like that i C. Instead I use #define
Like:
#define GROUPNAME_NAME
so in your case I would do
#define COUNTER_START 1
#define COUNTER_END 100
In C++ I would do:
const unsigned int COUNTER_START = 1;
const unsigned int COUNTER_END = 100;
The difference between C and C++ is due to differences in language specification.
I am trying to do the following but am getting the following error:
"error: expected expression before { token
Test_Stubs.h
#define SIGNATURE 0x78,0x9c
Test.c
#include "Test_Stubs.h"
static unsigned myArray[100];
static void
setup(void)
{
myArray = {SIGNATURE};
}
EDIT
Follow on question:
Is there a way to assign the individual values in the #define to specific indexes of myArray? For instance...
#include "Test_Stubs.h"
static unsigned myArray[100];
static void
setup(void)
{
myArray[0] = SIGNATURE[0]; //0x78
myArray[1] = SIGNATURE[1]; //0x9c
}
Clearly the above code will not code as SIGNATURE is neither an array or pointer.
As per the C syntax rules, you can only initialize an array using a brace enclosed initializer list at the time of definition.
Afterwards, you have to initialize element by element, using a loop, or, if you need to initialize all the elements to the same value, you can consider using memset().
EDIT:
No, as I mentioned in my comments, as per your code snippet, SIGNATURE is neither an array name, nor represent any array type, so you cannot use indexing on that.
However, using compound literal (on and above C99), if you change your #define, then, somehow, you can make this work. See the below code for example,
#include <stdio.h>
#define SIGNATURE ((unsigned [100]){0x78,0x9c})
static unsigned myArray[100];
int main (void)
{
myArray[0] = SIGNATURE[0]; //0x78
myArray[1] = SIGNATURE[1]; //0x9c
return 0;
}
See a LIVE VERSION
I came across this simple program somewhere
#include<stdio.h>
#include<stdlib.h>
char buffer[2];
struct globals {
int value;
char type;
long tup;
};
#define G (*(struct globals*)&buffer)
int main ()
{
G.value = 233;
G.type = '*';
G.tup = 1234123;
printf("\nValue = %d\n",G.value);
printf("\ntype = %c\n",G.type);
printf("\ntup = %ld\n",G.tup);
return 0;
}
It's compiling (using gcc) and executing well and I get the following output:
Value = 233
type = *
tup = 1234123
I am not sure how the #define G statement is working.
How G is defined as an object of type struct globals ?
First, this code has undefined behavior, because it re-interprets a two-byte array as a much larger struct. Therefore, it is writing past the end of the allocated space. You could make your program valid by using the size of the struct to declare the buffer array, like this:
struct globals {
int value;
char type;
long tup;
};
char buffer[sizeof(struct globals)];
The #define is working in its usual way - by providing textual substitutions of the token G, as if you ran a search-and-replace in your favorite text editor. Preprocessor, the first stage of the C compiler, finds every entry G, and replaces it with (*(struct globals*)&buffer).
Once the preprocessor is done, the compiler sees this code:
int main ()
{
(*(struct globals*)&buffer).value = 233;
(*(struct globals*)&buffer).type = '*';
(*(struct globals*)&buffer).tup = 1234123;
printf("\nValue = %d\n",(*(struct globals*)&buffer).value);
printf("\ntype = %c\n",(*(struct globals*)&buffer).type);
printf("\ntup = %ld\n",(*(struct globals*)&buffer).tup);
return 0;
}
The macro simply casts the address of the 2-character buffer buf into a pointer to the appropriate structure type, then de-references that to produce a struct-typed lvalue. That's why the dot (.) struct-access operator works on G.
No idea why anyone would do this. I would think it much cleaner to convert to/from the character array when that is needed (which is "never" in the example code, but presumably it's used somewhere in the larger original code base), or use a union to get rid of the macro.
union {
struct {
int value;
/* ... */
} s;
char c[2];
} G;
G.s.value = 233; /* and so on */
is both cleaner and clearer. Note that the char array is too small.
I'm trying to initialize a const struct with a designated initializer. However, one of the struct elements is a fixed-width array. I already have the contents I would like to initialize the array with in another fixed-width array of appropriate size.
Is there any way to do this with a designated initializer? A simple (failing example) of what I'm trying to accomplish is demonstrated below.
struct foo {
uint8_t array1[4];
uint8_t array2[4];
}
uint8_t array[4] = {
1, 2, 3, 4
};
struct foo const bar = {
.array1 = array, // incompatible pointer to integer conversion
.array2 = { *array } // only copies the first element
};
Short answer: you can't. C does not copy arrays (without the use of (standard library-)functions). The warnings come from the fact that you cannot assign an array as a whole, even when they are static or constant. When an array is used as an r-value in an assignment it decays to a pointer and thus cannot be assigned to another array (as a whole).
The easiest way to go would be to use memcpy, but obviously that must be inside a function.
If bar has global scope, or is declared static, then you won't be able use designated initializers to initialize from non-immediate values, regardless of whether or not the members in question are arrays.
However, if:
bar is declared on the stack of some function, and
Your fixed-size array really does only have 4 elements,
then you might be able to get away with something like this:
#include <stdio.h>
#include <stdint.h>
struct foo {
uint8_t array1[4];
uint8_t array2[4];
};
#define ARRAY_INIT(a) { a[0], a[1], a[2], a[3] }
int main (int argc, char **argv) {
uint8_t arr_init[4] = {
1, 2, 3, 4
};
struct foo const bar = {
.array1 = ARRAY_INIT(arr_init),
.array2 = ARRAY_INIT(arr_init),
};
printf("%d, %d\n", bar.array1[0], bar.array2[3]);
return (0);
}
The initializer array must appear before what is being initialized in the stack frame. Or it may come from a function parameter.
Of course if your array is much bigger than this, then using a macro like this will get very messy indeed.
While you may not be able to initialize the array by copying from another array, it may be helpful to use a preprocessor macro:
#define ARRAY_INIT {1, 2, 3, 4}
struct foo const bar = {
.array1 = ARRAY_INIT,
.array2 = ARRAY_INIT
};
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).