SWAPマクロ改良

主な変更点

  • コメント整備
  • 入れ替えるオブジェクトのサイズチェックを行い、サイズが異なる場合、入れ替えを行わないに修正。
  • サンプルドライバ結果表示の改善
  • 識別子が衝突しにくいように、一時変数名、型名を長くした。
#include <stdio.h>

/* オブジェクトa, bの値を入れ替えるマクロ関数 */
/* note: a, bは代入可能なオブジェクトを渡すこと */
/* 		 sizeof a, sizeof bが異なる場合何もしない。 */
/* 		 a, bに識別子swapMacroTmpを与えると誤動作する。 */
/* 		 既存コードにstruct TTmpSWAP_MACROがあるとコンパイルエラー */
#define SWAP(a, b)	do{ \
	struct TTmpSWAP_MACRO { \
		char buf[sizeof(a)]; \
	} swapMacroTmp; \
	 \
	if (sizeof(a) == sizeof(b)) { \
		swapMacroTmp = *((struct TTmpSWAP_MACRO *)&(a)); \
		*((struct TTmpSWAP_MACRO *)&(a)) = *((struct TTmpSWAP_MACRO *)&(b)); \
		*((struct TTmpSWAP_MACRO *)&(b)) = swapMacroTmp; \
	} \
}while(0)

/* 動作確認用構造体 */
/* printfで表示しやすいように4バイトに合わせただけ */
typedef struct THoge {
	char a;
	char b;
	char c;
	char d;
} THoge;

/* XOR版swap関数 */
void swap(int *a,  int *b)  {
	*a = *a ^ *b;
	*b = *b ^ *a;
	*a = *a ^ *b;
}

/* 使い方サンプルドライバ */
int main(void)
{
	int iA = 0xfedcba98, iB = 0x12345678;
	float fA = 0.0, fB = 3.14;
	int *pA = &iA, *pB = &iB;
	THoge tA = {1, 2, 3, 4}, tB = {9, 8, 7, 6};
	char strA[] = "123", strB[] = "abc";

	/* intの入れ替え */
	printf("\n ==== swap int ====\n");
	printf("before: %08x, %08x\n", iA, iB);
	SWAP(iA, iB);
	printf("after:  %08x, %08x\n", iA, iB);

	/* floatの入れ替え */
	printf("\n ==== swap float ====\n");
	printf("before: %08x, %08x\n", *((int *)&fA), *((int *)&fB));
	SWAP(fA, fB);
	printf("after:  %08x, %08x\n", *((int *)&fA), *((int *)&fB));
	
	/* ポインタの入れ替え */
	printf("\n ==== swap pointer ====\n");
	printf("before: %p, %p\n", pA, pB);
	SWAP(pA, pB);
	printf("after:  %p, %p\n", pA, pB);

	/* 構造体の入れ替え */
	printf("\n ==== swap struct ====\n");
	printf("before: %08x, %08x\n", *((int *)&tA), *((int *)&tB));
	SWAP(tA, tB);
	printf("after:  %08x, %08x\n", *((int *)&tA), *((int *)&tB));

	/* 配列の入れ替え */
	printf("\n ==== swap array ====\n");
	printf("before: %08x, %08x\n", *((int *)strA), *((int *)strB));
	SWAP(strA, strB);
	printf("after:  %08x, %08x\n", *((int *)strA), *((int *)strB));

	/* intの入れ替え同じオブジェクト */
	printf("\n ==== swap int(same object) ====\n");
	printf("before: %08x, %08x\n", iA, iA);
	SWAP(iA, iA);
	printf("after:  %08x, %08x\n", iA, iA);
	
	/* intの入れ替え同じオブジェクトXOR版 */
	printf("\n ==== (XOR ver)swap int(same object) ====\n");
	printf("before: %08x, %08x\n", iA, iA);
	swap(&iA, &iA);	/* 同じオブジェクトを渡すと値が失われる。 */
	printf("after:  %08x, %08x\n", iA, iA);
	
	return 0;
}

実行結果

$ ./main

 ==== swap int ====
before: fedcba98, 12345678
after:  12345678, fedcba98

 ==== swap float ====
before: 00000000, 4048f5c3
after:  4048f5c3, 00000000

 ==== swap pointer ====
before: 0x22cd64, 0x22cd60
after:  0x22cd60, 0x22cd64

 ==== swap struct ====
before: 04030201, 06070809
after:  06070809, 04030201

 ==== swap array ====
before: 00333231, 00636261
after:  00636261, 00333231

 ==== swap int(same object) ====
before: 12345678, 12345678
after:  12345678, 12345678

 ==== (XOR ver)swap int(same object) ====
before: 12345678, 12345678
after:  00000000, 00000000