C语言 在 C 中实现通用交换宏

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3982348/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 06:45:24  来源:igfitidea点击:

Implement generic swap macro in C

cfunctionmacrosgenerics

提问by Mohit Dhuper

Possible Duplicate:
is there an equivalent of std::swap() in c

可能的重复:
在 c 中是否有等价的 std::swap()

Hi folks,

嗨伙计,

I was attempting a problem to write a generic swap macro in C and my macro looks like this:

我试图在 C 中编写一个通用交换宏的问题,我的宏如下所示:

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

It works fine for integers and floats but I am unsure if there is any catch in it. What if by generic macro they mean swapping pointers, characters etc ? Can anyone help me with writing a generic macro for swapping every input ?

它适用于整数和浮点数,但我不确定其中是否有任何问题。如果通用宏是指交换指针、字符等会怎样?谁能帮我写一个通用的宏来交换每个输入?

Thanks

谢谢

回答by adamk

This works well only with integers.

这仅适用于整数。

For floats it will fail (e.g. try running it with a very large float and a very small one).

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

I would suggest something as follows:

我建议如下:

#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 is pretty optimized when the amount to copy is known at compilation time. Also, there's no need to manually pass a type name or use compiler specific extensions.

当在编译时知道要复制的数量时,memcpy 就得到了很好的优化。此外,无需手动传递类型名称或使用特定于编译器的扩展。

回答by Paul R

You can do something like this:

你可以这样做:

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

which you would then invoke like this:

然后你会像这样调用它:

SWAP(a, b, int);

or:

或者:

SWAP(x, y, float);

If you are happy to use gcc-specific extensions then you can improve on this like so:

如果您乐于使用特定于 gcc 的扩展,那么您可以像这样改进:

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

and then it would just be:

然后就是:

SWAP(a, b);

or:

或者:

SWAP(x, y);

This works for most types, including pointers.

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

Here is a test program:

这是一个测试程序:

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

回答by Jens Gustedt

GMan started this attempt, to code this in combination of an inlinefunction and a macro. This solution supposes that you have modern C compiler that supports C99, since it uses a compound literal:

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

This has the following properties:

这具有以下属性:

  • It evaluates each of aand bonly once.
  • It has a compile time check for the correct sizes.
  • It has no naming issue with a hidden variable.
  • The size of the temporary variable is computed at compile time, so the compound literal is not a dynamic array.
  • 它评估每一个a并且b只评估一次。
  • 它有一个编译时检查正确的大小。
  • 它没有隐藏变量的命名问题。
  • 临时变量的大小在编译时计算,因此复合文字不是动态数组。

The cast (ptrdiff_t)is needed such that the -1is not silently promoted to SIZE_MAX.

(ptrdiff_t)需要演员阵容,以便-1不会默默地提升为SIZE_MAX

This solution still suffers from two drawbacks:

该解决方案仍然存在两个缺点:

  1. It is not type safe. It only checks for the sizes of the types, not their semantics. If the types differ, say a doubleof size 8 and a uint64_t, you are in trouble.

  2. The expressions must allow the &operator to be applicable. Thus it will not work on variables that are declared with the registerstorage class.

  1. 它不是类型安全的。它只检查类型的大小,而不检查它们的语义。如果类型不同,比如double大小为 8 的 a 和 a uint64_t,你就有麻烦了。

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

回答by Mr. Llama

Simply put:you cannot make a genericswap macro in C, at least, not without some risk or headache. (See other posts. Explanation lies below.)

简单地说:你不能在 C 中创建一个通用的交换宏,至少,不是没有一些风险或头痛。(见其他帖子。解释在下面。)

Macros are nice, but the problem you'll run into with actual code would be data type issues (as you've stated). Furthermore, macros are "dumb" in a way. For example:

宏很好,但是您在实际代码中遇到的问题是数据类型问题(如您所说)。此外,宏在某种程度上是“愚蠢的”。例如:

With your example macro #define swap(x,y) { x = x + y; y = x - y; x = x - y; }, swap(++x, y)turns into { ++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;}.

If you ran int x = 0, y = 0; swap(++x, y);you'd get x=2, y=3instead of x=0, y=0. On top of this, if any of the temp variables in your macro appear in your code, you could run into some annoying errors.

如果你跑了,int x = 0, y = 0; swap(++x, y);你会得到x=2, y=3而不是x=0, y=0. 最重要的是,如果您的宏中的任何临时变量出现在您的代码中,您可能会遇到一些烦人的错误。

The functionality you're looking for were introduced in C++ as templates. The closest you can get in C is using an inline function for each data type imaginable or a decently complex macro (see previous macro issues and previous posts).

您正在寻找的功能是在 C++ 中作为模板引入的。您可以在 C 中获得的最接近的是为每个可以想象的数据类型或相当复杂的宏使用内联函数(请参阅以前的宏问题和以前的帖子)。

Here's what that the solution using templates in C++ looks like:

下面是在 C++ 中使用模板的解决方案的样子:

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

In C you'd need something like:

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

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

or (as mentioned a few times) a fairly complex macro which has potential to be hazardous.

或者(如多次提到的)一个相当复杂的宏,它有可能是危险的。

回答by JaredPar

This does not necessarily work fine for intaccording to the standand. Imagine the case where xand ywere INT_MAXand INT_MAX-1respectively. The first addition statement would result in a signed overflow which is undefined by the standard.

int根据标准,这不一定能正常工作。想象一下 wherexywasINT_MAXINT_MAX-1分别的情况。第一个加法语句将导致标准未定义的有符号溢出。

A more reliable implementation of the swap macro for intwould be the XOR swap algorithm

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

回答by Secure

Seriously, how many swaps do you have to do in your code that it is worth all the headaches coming up here in this thread with the given solutions? I mean, this is not a 10 line complicated and error prone code structure, it is a well-known idiom with one temporary variable and three simple assignments. Write it where you need it, even in one line if you want to save space:

说真的,您必须在代码中进行多少次交换,才能使用给定的解决方案在此线程中出现所有令人头疼的问题?我的意思是,这不是一个 10 行复杂且容易出错的代码结构,它是一个众所周知的习惯用法,只有一个临时变量和三个简单的赋值。把它写在你需要的地方,如果你想节省空间,即使在一行:

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

Or use a "local" macro where a and b are more complex.

或者使用“本地”宏,其中 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