Moh*_*per 27 c generics macros function
可能重复:
c中是否有等效的std :: swap()
嗨伙计,
我试图在C中编写一个通用交换宏的问题,我的宏看起来像这样:
#define swap(x,y) { x = x + y; y = x - y; x = x - y; }
Run Code Online (Sandbox Code Playgroud)
它适用于整数和浮点数,但我不确定它是否有任何捕获.如果通用宏意味着交换指针,字符等怎么办?任何人都可以帮我写一个通用宏来交换每个输入吗?
谢谢
ada*_*amk 77
这只适用于整数.
对于浮子,它将失败(例如,尝试使用非常大的浮子和非常小的浮子运行它).
我建议如下:
#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)
Run Code Online (Sandbox Code Playgroud)
当在编译时知道要复制的数量时,memcpy非常优化.此外,无需手动传递类型名称或使用特定于编译器的扩展.
Pau*_*l R 59
你可以这样做:
#define SWAP(x, y, T) do { T SWAP = x; x = y; y = SWAP; } while (0)
Run Code Online (Sandbox Code Playgroud)
你会像这样调用它:
SWAP(a, b, int);
Run Code Online (Sandbox Code Playgroud)
要么:
SWAP(x, y, float);
Run Code Online (Sandbox Code Playgroud)
如果您乐意使用特定于gcc的扩展,那么您可以这样改进:
#define SWAP(x, y) do { typeof(x) SWAP = x; x = y; y = SWAP; } while (0)
Run Code Online (Sandbox Code Playgroud)
然后它只会是:
SWAP(a, b);
Run Code Online (Sandbox Code Playgroud)
要么:
SWAP(x, y);
Run Code Online (Sandbox Code Playgroud)
这适用于大多数类型,包括指针.
这是一个测试程序:
#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;
}
Run Code Online (Sandbox Code Playgroud)
Jen*_*edt 11
GMan开始了这种尝试,将inline函数和宏结合起来进行编码.此解决方案假设您具有支持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))
Run Code Online (Sandbox Code Playgroud)
这具有以下属性:
a和b唯一的一次.(ptrdiff_t)需要演员阵容,-1以免被无声地提升SIZE_MAX.
该解决方案仍然存在两个缺点:
它不是类型安全的.它只检查类型的大小,而不是它们的语义.如果类型不同,比如说double大小为8和a uint64_t,那你就麻烦了.
表达式必须允许&运算符适用.因此,它不适用于使用register
存储类声明的变量.
简单地说:你不能在C中创建一个通用交换宏,至少,没有一些风险或头痛.(见其他帖子.解释如下.)
宏很好,但是你遇到的实际代码问题就是数据类型问题(如你所说).此外,宏在某种程度上是"愚蠢的".例如:
使用示例宏#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;}.
如果你跑了,int x = 0, y = 0; swap(++x, y);你会得到x=2, y=3而不是x=0, y=0.除此之外,如果宏中的任何临时变量出现在您的代码中,您可能会遇到一些烦人的错误.
您正在寻找的功能是作为模板在C++中引入的.你可以在C中得到的最接近的是对每种可以想象的数据类型使用内联函数或者是一个相当复杂的宏(参见前面的宏问题和之前的帖子).
以下是使用C++中的模板的解决方案:
template<typename T>
inline void swap(T &x, T &y)
{
T tmp = x;
x = y; y = tmp;
}
Run Code Online (Sandbox Code Playgroud)
在C中你需要这样的东西:
inline void swap_int(int *x, int *y) { /* Code */ }
inline void swap_char(char *x, char *y) { /* Code */ }
// etc.
Run Code Online (Sandbox Code Playgroud)
或者(如提到的那样)一个相当复杂的宏,它有可能是危险的.