C 中的 Hygenic 宏

Hygenic macros in C

C FAQ 声明 C 中的通用 SWAP 宏基本上是不可能的,也不值得为此付出努力。这对我来说听起来像是一个挑战。

它列举了 2 个主要困难:

  1. 正在寻找合适的类型用作临时变量。有涉及 char[] 数组和 memcopy 的 hack,但这种解决方案在 SWAP(my_int, my_float) 之类的事情上失败了。许多编译器支持 decltype 风格的运算符,这使得这很容易,但它们是非标准的。现在我承认失败,只要求用户提供合适的类型作为第三个参数。
  2. 正在为临时变量找到一个安全的名称。这是我认为我有解决方案的事情。我可以使用字符串化运算符 # 将输入参数字符串化,并将它们与预期的临时变量名称进行比较以找到不匹配的名称。
#include <stdio.h>

#define SWAP(a,b,type)                          \
do {                                            \
    if ((#a[0] != 'a') && (#b[0] != 'a')){      \
        type a_temp = a;                        \
        a = b;                                  \
        b = a_temp;                             \
    }else                                       \
    if ((#a[0] != 'b') && (#b[0] != 'b')){      \
        type b_temp = a;                        \
        a = b;                                  \
        b = b_temp;                             \
    }else                                       \
    if ((#a[0] != 'c') && (#b[0] != 'c')){      \
        type c_temp = a;                        \
        a = b;                                  \
        b = c_temp;                             \
    }                                           \
} while(0)

int main()
{
    int a_temp = 10, b_temp = 20, c_temp = 30;

    printf("a_temp = %d, b_temp = %d, c_temp = %d\n", a_temp, b_temp, c_temp);
    SWAP(a_temp, b_temp, int);
    printf("a_temp = %d, b_temp = %d, c_temp = %d\n", a_temp, b_temp, c_temp);
    SWAP(a_temp, c_temp, int);
    printf("a_temp = %d, b_temp = %d, c_temp = %d\n", a_temp, b_temp, c_temp);
    SWAP(b_temp, c_temp, int);
    printf("a_temp = %d, b_temp = %d, c_temp = %d\n", a_temp, b_temp, c_temp);

    return 0;
}

我看到很多讨论都提到了误抓的问题,没有看到有人提到你可以这样做,无论是推荐还是谴责。这是个好主意吗?

如果变量是左值表达式,这在某些情况下会失败,例如,如果您有 int *a_tempint *b_temp,而您 SWAP(*a_temp, *b_temp, int)。并且由于宏正在静默使用 "common" 名称,如 a_temp,如果有类似 #define a_temp *a.

的名称,它可能会中断

无论如何,它可以说不是通用的,因为您必须传递类型:SWAP(a, b, int)SWAPINT(a, b) 没有根本区别。如果我们接受传递类型,是否也可以接受传递临时变量的名称?或者甚至是像 _tmpswap0123456789 这样的固定临时变量名称——毕竟,我们接受更常见的名称 SWAP 现在被定义为这个宏,所以担心里面的临时变量名称似乎中学