在C中实现通用交换宏

时间:2010-10-20 21:12:39

标签: c function macros generics

  

可能重复:
  is there an equivalent of std::swap() in c

嗨大家好,

我在C中编写通用交换宏时遇到了问题,我的宏看起来像这样:

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

它适用于整数和浮点数,但我不确定它是否有任何捕获。如果通用宏意味着交换指针,字符等怎么办?任何人都可以帮我编写一个通用宏来交换每个输入吗?

由于

6 个答案:

答案 0 :(得分:76)

这只适用于整数。

对于花车它会失败(例如尝试使用非常大的浮子和非常小的浮子运行它)。

我建议如下:

#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非常优化。 此外,无需手动传递类型名称或使用特定于编译器的扩展名。

答案 1 :(得分:57)

您可以这样做:

#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);

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

这是一个测试程序:

#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;
}

答案 2 :(得分:11)

GMan开始尝试,将inline函数与宏结合起来进行编码。此解决方案假设您拥有支持C99的现代C编译器,因为它使用compound literal

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))

这具有以下属性:

  • 它仅评估ab中的每一个 一次。
  • 它有一个编译时检查 正确的尺寸。
  • 隐藏时没有命名问题 变量
  • 临时变量的大小是 在编译时计算,所以 复合文字不是动态的 阵列。

需要广告(ptrdiff_t),以便-1不会默默地提升为SIZE_MAX

这种解决方案仍有两个缺点:

  1. 这不是类型安全的。它只检查 对于类型的大小,不是 他们的语义。如果是类型 不同,比如8 {8}的double 一个uint64_t,你遇到了麻烦。

  2. 表达式必须允许&运算符适用。从而 它不适用于使用register声明的变量 存储类。

答案 3 :(得分:9)

简单地说:你不能在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;
}

在C中你需要类似的东西:

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

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

答案 4 :(得分:0)

根据标准,这不一定适用于int。想象一下xy分别为INT_MAXINT_MAX-1的情况。第一个加法语句将导致签名溢出,标准未定义。

int的交换宏的更可靠的实现是XOR交换算法

答案 5 :(得分:-2)

说真的,你需要在你的代码中进行多少交换,以便在给定解决方案的这个帖子中出现所有令人头疼的问题?我的意思是,这不是一个10行复杂且容易出错的代码结构,它是一个众所周知的成语,有一个临时变量和三个简单的赋值。如果您想节省空间,请将其写在您需要的地方,即使是在一行中:

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

或者使用“本地”宏,其中a和b更复杂。

#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