在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))
这具有以下属性:
- 它只评估
a
和b
每a
。 - 它有一个编译时间检查正确的大小。
- 它没有隐藏variables的命名问题。
- 临时variables的大小是在编译时计算的,所以复合文字不是一个dynamic数组。
需要(ptrdiff_t)
,以使-1
不会静默地升级到SIZE_MAX
。
这个解决scheme仍然有两个缺点:
-
这不是types安全的。 它只检查types的大小,而不是它们的语义。 如果types不同,比如8号和
uint64_t
的double
,那么你就麻烦了。 -
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
。 想象一下x
和y
分别是INT_MAX
和INT_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