Assign an array or an integer without knowing its nature in the function code (but compiler knows)

帅比萌擦擦* 提交于 2020-03-24 14:15:50

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!