在C中实现generics交换macros

可能重复:
是否有一个相当于c中的std :: swap()

嗨伙计,

我试图在C编写一个通用的交换macros的问题,我的macros看起来像这样:

#define swap(x,y) { x = x + y; y = x - y; x = x - y; } 

它适用于整数和漂浮,但我不确定是否有任何捕获。 如果通过genericsmacros,他们是指交换指针,字符等? 任何人都可以帮我写一个通用的macros来交换每一个input?

谢谢

这只适用于整数。

对于浮动它将失败(例如尝试运行一个非常大的浮动和非常小的一个)。

我会build议如下:

 #define swap(x,y) do \ { unsigned char swap_temp[sizeof(x) == sizeof(y) ? (signed)sizeof(x) : -1]; \ memcpy(swap_temp,&y,sizeof(x)); \ memcpy(&y,&x, sizeof(x)); \ memcpy(&x,swap_temp,sizeof(x)); \ } while(0) 

memcpy在编译时知道要复制的数量时是非常优化的。 另外,不需要手动传递types名称或使用编译器特定的扩展名。

你可以做这样的事情:

 #define SWAP(x, y, T) do { T SWAP = x; x = y; y = SWAP; } while (0) 

然后你可以这样调用它:

 SWAP(a, b, int); 

要么:

 SWAP(x, y, float); 

如果你很乐意使用gcc特定的扩展,那么你可以改进如下:

 #define SWAP(x, y) do { typeof(x) SWAP = x; x = y; y = SWAP; } while (0) 

然后它会是:

 SWAP(a, b); 

要么:

 SWAP(x, y); 

这适用于大多数types,包括指针。

这是一个testing程序:

 #include <stdio.h> #define SWAP(x, y) do { typeof(x) SWAP = x; x = y; y = SWAP; } while (0) int main(void) { int a = 1, b = 2; float x = 1.0f, y = 2.0f; int *pa = &a; int *pb = &b; printf("BEFORE:\n"); printf("a = %d, b = %d\n", a, b); printf("x = %f, y = %f\n", x, y); printf("pa = %p, pb = %p\n", pa, pb); SWAP(a, b); // swap ints SWAP(x, y); // swap floats SWAP(pa, pb); // swap pointers printf("AFTER:\n"); printf("a = %d, b = %d\n", a, b); printf("x = %f, y = %f\n", x, y); printf("pa = %p, pb = %p\n", pa, pb); return 0; } 

GMan开始了这个尝试,把这个inline函数和macros组合在一起编码。 这个解决scheme假设你有一个支持C99的现代C编译器,因为它使用复合文字 :

 inline void swap_detail(void* p1, void* p2, void* tmp, size_t pSize) { memcpy(tmp, p1, pSize); memcpy(p1, p2, pSize); memcpy(p2 , tmp, pSize); } #define SWAP(a, b) swap_detail(&(a), &(b), (char[(sizeof(a) == sizeof(b)) ? (ptrdiff_t)sizeof(a) : -1]){0}, sizeof(a)) 

这具有以下属性:

  • 它只评估aba
  • 它有一个编译时间检查正确的大小。
  • 它没有隐藏variables的命名问题。
  • 临时variables的大小是在编译时计算的,所以复合文字不是一个dynamic数组。

需要(ptrdiff_t) ,以使-1不会静默地升级到SIZE_MAX

这个解决scheme仍然有两个缺点:

  1. 这不是types安全的。 它只检查types的大小,而不是它们的语义。 如果types不同,比如8号和uint64_tdouble ,那么你就麻烦了。

  2. expression式必须允许&运算符是适用的。 因此它不能用register存储类声明的variables。

简而言之,你不能在C语言中创build一个通用的交换macros,至less不能没有风险或头痛 。 (见其他post,说明位于下面)

macros是好的,但是你会遇到的问题与实际的代码将是数据types的问题(如你所说)。 而且,macros在某种程度上是“愚蠢的”。 例如:

用你的例子macros#define swap(x,y) { x = x + y; y = x - y; x = x - y; } #define swap(x,y) { x = x + y; y = x - y; x = x - y; } #define swap(x,y) { x = x + y; y = x - y; x = x - y; }swap(++x, y)变成{ ++x = ++x + y; y = ++x - y; ++x = ++x - y;} { ++x = ++x + y; y = ++x - y; ++x = ++x - y;} { ++x = ++x + y; y = ++x - y; ++x = ++x - y;}

如果你运行int x = 0, y = 0; swap(++x, y); int x = 0, y = 0; swap(++x, y); 你会得到x=2, y=3而不是x=0, y=0 。 最重要的是,如果macros中的任何临时variables出现在你的代码中,你可能会遇到一些恼人的错误。

你正在寻找的function是作为模板在C ++中引入的。 您可以在C中得到最接近的是使用内联函数为每个可以想象的数据types或一个体面复杂的macros(请参阅以前的macros问题和以前的post)。

以下是在C ++中使用模板的解决scheme:

 template<typename T> inline void swap(T &x, T &y) { T tmp = x; x = y; y = tmp; } 

在C中,你需要这样的东西:

 inline void swap_int(int *x, int *y) { /* Code */ } inline void swap_char(char *x, char *y) { /* Code */ } // etc. 

或者(如前所述)是一个相当复杂的macros,有可能是危险的。

根据标准,这不一定适用于int 。 想象一下xy分别是INT_MAXINT_MAX-1情况。 第一个附加语句会导致标准的未定义的有符号溢出。

交换macros的int更可靠的实现将是XOR交换algorithm

严重的是,在你的代码中你需要做多less次交换,在给定的解决scheme中,在这个线程中,所有的头痛都是值得的。 我的意思是,这不是一个十行复杂且容易出错的代码结构,它是一个众所周知的习惯用一个临时variables和三个简单的作业。 把它写在你需要的地方,如果你想节省空间,甚至可以在一行:

 function foo () { int a, b, tmp; ... tmp = a; a = b; b = tmp; .... } 

或者使用a和b更复杂的“本地”macros。

 #define SWAP(t,a,b) ( (t) = (a), (a) = (b), (b) = (t) ) function foo (pointer) { int tmp; ... SWAP(tmp, pointer->structure.array[count+1], pointer->structure.array[count+2]); ... } #undef SWAP