C言語:10行で暗号化プログラム

10行プログラムカテゴリのアイキャッチ画像10行以内のプログラム
スポンサーリンク

入力した数値が暗号化されて、再度暗号化された数値を入力すると元の数に戻るという不思議なプログラムをC言語で紹介します。
今回は、コメントを入れて10行です。

xAngou.c

/* xAngou.c: 簡易暗号化プログラム */
#include <stdio.h>
int main(void)
{
	int x;
	printf("number? ");
	scanf("%d", &x);
	printf("result: %d\n", x ^ 0x1234);
	return 0;
}

実行結果

最初に適当な数値2525を入力

number? 2525
result: 7145

再度実行し先ほど表示された7145を入力すると…

number? 7145
result: 2525

元の数2525に戻ります!
ぜひ、他の数値でも試してみてください。
不思議ですね!

でもC言語は、ビット演算が可能な言語ですのでちっとも不思議ではありません。
以下解説です。

スポンサーリンク

C言語のビット演算子

ビット演算に使用できるC言語の演算子には次のものがあります。

ビット演算子意味使用例意味
&ビット毎の論理積a & 10変数aと00001010の論理積
|ビット毎の論理和a | 10変数aと00001010の論理和
^ビット毎の排他的論理和a ^ 10変数aと00001010の排他的論理和
<<ビット左シフトa << 2変数aの値を2ビット左にシフトする
>>ビット右シフトa >> 2変数aの値を2ビット右にシフトする
~ビット毎の反転~a変数aをビット反転する

ビット演算は、2つのビット同士の計算に使います。

単純に1ビットで考えます。
aが1、bが0とします。

a & b の結果は 0です。掛け算として考えると分かりやすいです。
a | b の結果は、1です。どちらか一方が1なら1になるという考え方です。

全てのパターンを表にするとこうなります。

a & b(どちらかが0なら結果は0)

ab結果
000
100
010
111

a | b(どちらか一方が1なら結果は1)

ab結果
000
101
011
111

今回使った排他的論理和a ^ bはどうでしょうか?
これも表で示します。

a ^ b

ab結果
000
101
011
110

不思議な結果です。
双方が同じ値(0と0又は1と1)の場合、0。
双方が違う値(1と0又は0と1)の場合、1
となります。

これを使うと先ほどの元に戻る数が実現できます。

2進数(ビット)に直して考える

プログラムで解説します。

int型だとビット数が大きいためchar型(1バイト=8ビット)の変数を使ったプログラムで説明します。

次のプログラムを見てください。

/* 排他的論理和の確認 */
#include <stdio.h>
int main(void)
{
	/* 元の数 */
	char x = 10;
	printf("%d\n", x);

	/* 排他的論理和の演算を実行 */
	x = x ^ 15;
	printf("%d\n", x);

	/* もう一度、排他的論理和の演算を実行 */
	x = x ^ 15;
	printf("%d\n", x);
	
	return 0;
}

実行結果

10
5
10

数値を全て2進数に置き換えると理解できます。

まずは最初の状態
変数の状態をビットで表した状態の画像

次に最初に排他的論理和のビット演算をした状態
排他的論理和のビット演算のイメージ画像1

もう一度排他的論理和のビット演算をした状態
排他的論理和のビット演算のイメージ画像2

見事元に戻りました!

最初に紹介した10行プログラムでは、以下の部分が排他的論理和の演算に当たります。

printf(“result: %d\n”, x ^ 0x1234);

16進数表記になっていますが、やっていることは一緒です。x ^ 0x12340x1234の箇所は適当な数値です。
他の数値にするとresultで表示される数値は変わりますが、元に戻ります。

ビット演算面白いですね!

コメント