【问题标题】:Use of pasting operator `##` with types in C在 C 中将粘贴运算符 `##` 用于类型
【发布时间】:2016-01-12 08:18:52
【问题描述】:

是否可以为 C 预处理器定义一个以数组为参数并扩展为 <type of array elements>_string 的宏?例如,如果x 在整数数组中,则使用参数x 调用的宏应扩展为int_string

我试过了

#define TypePaste(array) typeof(array[0])##_string

但它会扩展为)_string

即使对## 操作数使用多个间接级别,宏也无法正确展开。

【问题讨论】:

  • 将预处理器指令想象成一种在编译之前轮到它的愚蠢机制,用于字符串操作,其中字符串是代码行。
  • 有很多方法,但这取决于您是否希望宏创建新类型、新变量名或引用现有类型或变量。
  • 听起来有点像 xy 问题。你想达到什么目的?
  • @Ludin 宏应该扩展为现有函数的名称。我想为每个现有类型定义一个函数<type>_string,然后使用宏根据给定数组的类型选择正确的函数。
  • @JensGustedt 我想定义一个通用函数来对不需要将数组类型作为参数传递到的数组进行排序。

标签: c macros typeof


【解决方案1】:

这是不可能的。在扩展宏和连接标记的翻译阶段(预处理阶段),编译器(此时为预处理器)还没有类型的概念 因此不可能生成类型。

【讨论】:

  • 预处理是几个编号的翻译阶段之一,特别是阶段 4 (C11 §5.1.1.2)。
  • 所以没有办法让编译器先评估typeof(),或者在typeof()展开后以某种方式粘贴字符串?
  • @OscarCharles 不,没有。如果你想做这样的事情,你必须编写一个自定义代码生成器。如果您提出要通过这样做来解决的问题,也许我们可以找到不同的解决方案。
【解决方案2】:

目前还不是很清楚您要解决什么问题,但请给出您的评论:

宏应扩展为现有函数的名称。我想为每个现有类型定义一个函数<type>_string,然后使用宏根据给定数组的类型选择正确的函数。

然后你可以使用 C11 _Generic 关键字:

#include <stdio.h>

void int_string (size_t size, int array[size])
{
  printf("I am %s, do stuff here.\n", __func__);
}

void float_string (size_t size, float array[size])
{
  printf("I am %s, do stuff here.\n", __func__);
}

#define TypePaste(array)          \ 
  _Generic( array,                \
            int:   int_string,    \
            float: float_string ) \
  (sizeof(array)/sizeof(*array), array) // function parameters



int main()
{
  int   i_arr[5];
  float f_arr[3];

  TypePaste(i_arr);
  TypePaste(f_arr);
}

输出:

I am int_string, do stuff here.
I am float_string, do stuff here.

注意:这假定传递的参数是本地/文件范围分配的数组。如果传递指针,则没有类型安全,程序将失败。

【讨论】:

    【解决方案3】:

    C11 的_Generic 类型选择是做你想做的“正确”的方式。还有其他依赖于平台的解决方案,很难。

    如果你正在使用 gcc——你并没有明确地这么说,但是你已经使用了 gcc 的扩展 typeof——你可以使用 gcc 的 statement expresionsnested functions 当场为 qsort 创建一个比较函数:

    double a[5] = {8.4, 8.1, 9.3, 12.2, 5.2};
    
    qsort(a, 5, sizeof(*a), ({
        int cmp(const void *p, const void *q) {
            const typeof(a[0]) *pp = p;
            const typeof(a[0]) *qq = q;
    
            return (*pp < *qq) ? -1 : (*pp > *qq);
        }
        cmp;
    }));
    

    这将创建一个函数并返回其地址。 (复合表达式的最后一条语句是它的值。局部变量的范围是语句表达式,但嵌套函数不是在堆栈上创建的,因此返回指向该函数的指针是安全的。)

    对于原始类型,您希望根据比较运算符&lt;&gt; 进行排序,您可以将其转换为宏:

    #define COMPARE(ARRAY)({             \
            int cmp(const void *p, const void *q) {         \
                const typeof(ARRAY[0]) *pp = p;             \
                const typeof(ARRAY[0]) *qq = q;             \
                return (*pp < *qq) ? -1 : (*pp > *qq);      \
            }                                               \
            cmp;                                            \
        })
    
    qsort(a, 5, sizeof(*a), COMPARE(a));
    

    甚至:

    #define SORT(ARRAY, N)                                  \
        qsort(ARRAY, N, sizeof(*ARRAY), COMPARE(ARRAY))
    
    SORT(a, 5);
    

    这不是标准 C,所以如果你需要平台之间的兼容性,这是不可能的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-22
      • 2020-04-29
      • 2012-02-18
      • 1970-01-01
      • 2018-09-24
      相关资源
      最近更新 更多