我知道如何在c ++中交换2个变量,即你使用std::swap(a,b)
。
问题:
C
标准库是否具有与C ++ std::swap()
类似的功能,或者我是否必须自己定义它。
答案 0 :(得分:20)
是的,您需要自己定义。
void swap(void* a, void* b, size_t length)
,但与std::swap
不同,它不是类型安全的。inline
关键字),这很重要。我们也可以定义像
这样的宏#define SWAP(a,b,type) {type ttttttttt=a;a=b;b=ttttttttt;}
但它会隐藏ttttttttt
变量,您需要重复a
的类型。 (在gcc中有typeof(a)
来解决此问题,但您仍然无法SWAP(ttttttttt,anything_else);
。)
编写交换并不是那么困难 - 它只是3行简单的代码!
答案 1 :(得分:13)
C中没有等效物 - 事实上不可能,因为C没有模板功能。您必须为要交换的所有类型编写单独的函数。
答案 2 :(得分:9)
如果你不介意使用C语言的gcc扩展名typeof
,你可以用宏做类似的事情:
#include <stdio.h>
#define SWAP(a, b) do { typeof(a) temp = a; a = b; b = temp; } while (0)
int main(void)
{
int a = 4, b = 5;
float x = 4.0f, y = 5.0f;
char *p1 = "Hello";
char *p2 = "World";
SWAP(a, b); // swap two ints, a and b
SWAP(x, y); // swap two floats, x and y
SWAP(p1, p2); // swap two char * pointers, p1 and p2
printf("a = %d, b = %d\n", a, b);
printf("x = %g, y = %g\n", x, y);
printf("p1 = %s, p2 = %s\n", p1, p2);
return 0;
}
答案 3 :(得分:7)
这在Clang和gcc中很快起作用(但不是icc,它不能识别这个交换函数 - 但是,它会在任何标准的C99编译器中编译),只要优化实际上能识别交换(它们的确足够高)优化水平)。
#include <string.h>
#define SWAP(a, b) swap_internal(&(a), &(b), sizeof *(1 ? &(a) : &(b)))
static inline void swap_internal(void *a, void *b, size_t size) {
char tmp[size];
memcpy(tmp, a, size);
memmove(a, b, size);
memcpy(b, tmp, size);
}
现在解释它是如何工作的。首先,SWAP()
行相对比较奇怪,但实际上相对简单。 &(a)
是作为指针传递的参数a
。同样,&(b)
是作为指针传递的参数b
。
最有趣的代码是sizeof *(1 ? &(a) : &(b))
。这实际上是一个相对聪明的错误报告。如果不需要错误报告,则可能只是sizeof(a)
。三元运算符要求其运算具有兼容类型。在这种情况下,我通过将它们转换为指针来检查两个不同的参数,以确定它们的类型兼容性(否则,int
和double
将是兼容的)。由于int *
和double *
不兼容,编译将失败...前提是它是标准的C编译器。遗憾的是,在这种情况下,许多编译器都假设void *
类型,因此它失败了,但至少有一个警告(默认情况下启用)。为了确保结果的大小正确,该值将被取消引用,并应用于sizeof
,因此没有副作用。
~/c/swap $ gcc swap.c
swap.c: In function ‘main’:
swap.c:5:64: warning: pointer type mismatch in conditional expression [enabled by default]
#define SWAP(a, b) swap_internal(&(a), &(b), sizeof *(1 ? &(a) : &(b)))
^
swap.c:16:5: note: in expansion of macro ‘SWAP’
SWAP(cat, dog);
^
~/c/swap $ clang swap.c
swap.c:16:5: warning: pointer type mismatch ('int *' and 'double *') [-Wpointer-type-mismatch]
SWAP(cat, dog);
^~~~~~~~~~~~~~
swap.c:5:57: note: expanded from macro 'SWAP'
#define SWAP(a, b) swap_internal(&(a), &(b), sizeof *(1 ? &(a) : &(b)))
^ ~~~~ ~~~~
1 warning generated.
~/c/swap $ icc swap.c
swap.c(16): warning #42: operand types are incompatible ("int *" and "double *")
SWAP(cat, dog);
^
这个宏只评估一次(sizeof
是特殊的,因为它不评估它的参数)。这为array[something()]
之类的参数提供了安全性。我能想到的唯一限制是它不适用于register
变量,因为它依赖于指针,但除此之外,它是通用的 - 你甚至可以将它用于可变长度数组。它甚至可以处理交换相同的变量 - 而不是你想要这样做。
答案 4 :(得分:3)
在C中,这通常是使用宏来完成的,例如:#define SWAP(type,a,b) {type _tmp=a;a=b;b=_tmp;}
...但我不建议使用他们因为有一些不明显的缺陷。
这是为避免意外错误而编写的宏。
#define SWAP(type, a_, b_) \
do { \
struct { type *a; type *b; type t; } SWAP; \
SWAP.a = &(a_); \
SWAP.b = &(b_); \
SWAP.t = *SWAP.a; \
*SWAP.a = *SWAP.b; \
*SWAP.b = SWAP.t; \
} while (0)
SWAP(a[i++], b[j++])
不会产生问题副作用。SWAP
,以便在不同的名称碰巧与所选的硬编码名称冲突时不会导致错误。memcpy
(实际上我在测试中最终会进行真正的函数调用,即使编译器可能会优化它们)。答案 5 :(得分:0)
此处未提及的另一个宏:如果您提供临时变量,则无需提供类型。另外,逗号运算符在这里用于避免do-while(0)技巧。但通常我不在乎,只是写三个命令。另一方面,如果a和b更复杂,则临时宏很有用。
#define SWAP(a,b,t) ((t)=(a), (a)=(b), (b)=(t))
void mix_the_array (....)
{
int tmp;
.....
SWAP(pointer->array[counter+17], pointer->array[counter+20], tmp);
.....
}
#undef SWAP
答案 6 :(得分:0)
检查编译器文档。编译器可能具有用于交换字节的swapb
函数,并且我提供其他类似的函数。
最糟糕的情况是,浪费一天并写一些通用交换功能。它不会消耗大量项目的时间表。
答案 7 :(得分:0)
指针有三个部分,例如我们可以将short* p
分解为三个部分
void*p
读取两个字节,我们得到一个短整数。%hu
使用前两部分,我们将能够构建一个通用的交换函数:
#include<stdint.h>
#ifdef _WIN32
#define alloca _alloca
#else
#include <alloca.h>
#endif
void gswap(void * const a, void * const b, int const sz) {
// for most case, 8 bytes will be sufficient.
int64_t tmp; // equivalent to char tmp[8];
void * p;
bool needfree = false;
if (sz > sizeof(int64_t)) {
// if sz exceed 8 bytes, we allocate memory in stack with little cost.
p = alloca(sz);
if (p == NULL) {
// if sz is too large to fit in stack, we fall back to use heap.
p = malloc(sz);
//assert(p != NULL, "not enough memory");
needfree = true;
}
}
else {
p = &tmp;
}
memcpy(p, b, sz);
memcpy(b, a, sz);
memcpy(a, p, sz);
if (needfree) {
free(p);
}
}
e.g:
{// swap int
int a = 3;
int b = 4;
printf("%d,%d\n", a, b);//3,4
gswap(&a, &b, sizeof(int));
printf("%d,%d\n", a, b);//4,3
}
{// swap int64
int64_t a = 3;
int64_t b = 4;
printf("%lld,%lld\n", a, b);//3,4
gswap(&a, &b, sizeof(int64_t));
printf("%lld,%lld\n", a, b);//4,3
}
{// swap arrays
int64_t a[2] = { 3,4 };
int64_t b[2] = { 5,6 };
printf("%lld,%lld,%lld,%lld\n", a[0], a[1], b[0], b[1]);//3,4,5,6
gswap(&a, &b, sizeof(a));
printf("%lld,%lld,%lld,%lld\n", a[0], a[1], b[0], b[1]);//5,6,3,4
}
{// swap arrays
double a[2] = { 3.,4. };
double b[2] = { 5.,6. };
printf("%lf,%lf,%lf,%lf\n", a[0], a[1], b[0], b[1]);//3.000000, 4.000000, 5.000000, 6.000000
arrswap(&a, &b, sizeof(a));
printf("%lf,%lf,%lf,%lf\n", a[0], a[1], b[0], b[1]);//5.000000, 6.000000, 3.000000, 4.000000
}
答案 8 :(得分:0)
其他答案中有很多不错的解决方案!在阅读K&R时,我想到了另一个C的快速交换宏:
#define SWAP(TYPE,x,y) TYPE a = x, x=y, y=a
答案 9 :(得分:0)
一些交换机制涉及-
//( Not quite good, try passing ++x and ++y as arguments :-} )
#define SWAP_0(x,y) { x = x+y; \
y = x-y; \
x = x-y; }
//Faster than SWAP_0
#define SWAP_1(x,y) { x ^= y; \
y ^= x; \
x ^= y; }
//Optimal for general usage
#define SWAP_2(x,y) \
do \
{ \
uint8_t __temp[sizeof(x) == sizeof(y) ? (signed)sizeof(x) : -1]; \
memcpy(__temp, &y, sizeof(x)); \
memcpy( &y, &x, sizeof(x)); \
memcpy( &x, __temp, sizeof(x)); \
} while(0)
//using GCC specific extension
#define SWAP_3(x, y) do \
{ \
typeof(x) SWAP_3 = x; x = y; y = SWAP_3; \
}while (0)
//without GCC specific extension - can be invoked like this - SWAP_3(x,y, int) or SWAP_3(x,y, float)
#define SWAP_4(x, y, T) do \
{ \
T SWAP_4 = x; x = y; y = SWAP_4; \
}while (0)
答案 10 :(得分:-2)
您可以使用宏执行类似操作,而不使用临时变量。
#include <stdio.h>
#define SWAP(a, b) {a=a+b;b=a-b;a=a-b;} //swap macro
int main(void)
{
int a = 4, b = 5;
float x = 4.0f, y = 5.0f;
char *p1 = "Hello";
char *p2 = "World";
a = 4, b = 5,x = 4.0f, y = 5.0f,*p1 = "Hello",*p2="world";
SWAP(a, b); // swap two ints, a and b
SWAP(x, y); // swap two floats, x and y
SWAP1p1, p2); // swap two char * pointers, p1 and p2
printf("a = %d, b = %d\n", a, b);
printf("x = %g, y = %g\n", x, y);
printf("p1 = %s, p2 = %s\n", p1, p2);
return 0;
}
答案 11 :(得分:-2)
如果是数值(至少):
我知道这不是一个实际或完整的答案,但是直到现在每个人都在使用临时变量,所以我认为Chris Taylors blog可能与之相关,它确实消除了对typeof()等的需要。
a = a ^ b;
b = a ^ b;
a = a ^ b;
或
a = a + b;
b = a - b;
a = a - b;
理论上我认为这些技术也可以应用于字符串和其他类型。
仍然只有三个操作。