问题
I'm looking for something like this snippet. I expect it to know, at compile time, wether it is dealing with an array or not, and avoid the following errors.
#include <stdio.h>
#define IS_ARRAY(x,type) _Generic((&x), \
type (*)[]: 1, \
default: 0)
#define GENERIC_ASSIGN(arg,type) if(IS_ARRAY(arg,type)){arg[0] = 1; arg[1] = 2;}else{arg = 2;}
int main(void)
{
int foo = 0;
int bar[10] = {0};
GENERIC_ASSIGN(bar,int); //--> error: assignment to expression with array type
GENERIC_ASSIGN(foo,int); //--> error: subscripted value is neither array nor pointer nor vector "arg[0] = 1; arg[1] = 2;"
return 0;
}
When I do write GENERIC_ASSIGN(bar,int) i do know that 'bar' is an ARRAY, so does the compiler.
See this topic that explains one part of the problem here
The problem would have been solved easily if '#if' were allowed inside macros
回答1:
You can't assign to arrays, so you will have to use memcpy. For example, have the macro create a compound literal of all initializers and then memcpy that one.
#include <stdio.h>
#include <string.h>
#define IS_ARRAY(x,type) _Generic((&x), \
type (*)[]: 1, \
default: 0)
#define INIT(arg, type, ...) memcpy(&(arg), \
(type[]){__VA_ARGS__}, \
sizeof((type[]){__VA_ARGS__}))
#define GENERIC_ASSIGN(arg,type) IS_ARRAY(arg,type) ? \
INIT(arg,type,1,2) : \
INIT(arg,type,2)
int main(void)
{
int foo = 0;
int bar[10] = {0};
GENERIC_ASSIGN(bar,int);
GENERIC_ASSIGN(foo,int);
printf("%d %d\n",bar[0], bar[1]);
printf("%d\n",foo);
return 0;
}
Notably, with this method it doesn't really matter what type you use, array or not. The size of the initializer list is all that matters.
gcc -O2 resolves this into a couple of register loads (x86):
mov edx, 2
mov esi, 1
xor eax, eax
mov edi, OFFSET FLAT:.LC0
call printf
mov esi, 2
mov edi, OFFSET FLAT:.LC1
xor eax, eax
call printf
来源:https://stackoverflow.com/questions/60657169/assign-an-array-or-an-integer-without-knowing-its-nature-in-the-function-code-b