【问题标题】:Assign an array or an integer without knowing its nature in the function code (but compiler knows)在函数代码中不知道其性质的情况下分配数组或整数(但编译器知道)
【发布时间】:2020-06-24 16:26:10
【问题描述】:

我正在寻找类似 sn-p 的东西。 我希望它在编译时知道它是否正在处理数组,并避免以下错误。

#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;
}

当我写 GENERIC_ASSIGN(bar,int) 时,我确实知道 'bar' 是一个数组,编译器也是。

请参阅此主题以解释问题的一部分here

如果在宏中允许使用“#if”,问题就会很容易解决

【问题讨论】:

  • 也许this article 有帮助?它展示了如何创建 IF_ELSE 宏。
  • 不,这无济于事IF_ELSE(IS_ARRAY(bar,int))(printf("is_array"))(printf("is_not_array")); >> error: expected expression before ‘int’; IS_ARRAY 在 IF_ELSE 之后扩展,所以它扩展为 _IF_IS_ARRAY,但我需要 _IF_1 或 _IF_0.... 但无论如何,这篇文章很有趣
  • 注意:我会在 x 周围使用 ()_Generic((&amp;(x)), type (*)[]: 1, default: 0)
  • 详细信息:“分配一个数组...”在 C 中是不可能的。代码可以初始化一个数组,但不能分配它,即使int bar[10] = {0}; 看起来像一个作业。无法分配 bar = {0};bar = (char [10]){0};。那么,Guillaume D,您的目标是分配一个数组(以某种方式)或初始化它还是其他什么?
  • @chux-ReinstateMonica 没有多少表达式会产生左值,所以它并不是那么重要,除非您计划将赋值表达式分配给宏......这在数组的情况下是不可能的。

标签: c arrays macros compile-time


【解决方案1】:

你不能分配给数组,所以你必须使用 memcpy。例如,让宏创建所有初始值设定项的复合文字,然后 memcpy 那个。

#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;
}

值得注意的是,使用这种方法,您使用什么类型(数组与否)并不重要。初始化列表的大小才是最重要的。

gcc -O2 将其解析为几个寄存器加载 (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

【讨论】:

  • 感谢@Lundin 回答了我所有的问题:D
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-03-05
  • 1970-01-01
  • 1970-01-01
  • 2020-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多