C言語の文字と文字の字面値を探究する

4298 ワード

本文はshimachaoのブログからhttp://blog.csdn.net/shimachao/article/details/8264676転載は出典を明記してください.
文字char:
       C言語の文字型は実は1種の整数型です.int型のようにchar(文字)変数を演算することができます.具体的にはchar変数をchar型変数と解釈するかint型変数と解釈するかはプログラムによって決まる.int型変数とchar型変数は、charの表現範囲を超えない限り、一致して付与することもできる.たとえば、次のようになります.
char ch = 'a';
printf("%c,%d
",ch,ch);

a,97が印刷されます
すなわちchは文字aと解釈してもよいし、整数97と解釈してもよい.
文字のフォント値(文字定数とも呼ばれる場合もあります):
       まず字面値の意味を話します:字面値は1種の記号で、例えば3100、a、c、3.14です.私たちはそれを修正できないので(3を5に変更してもいいですか?)時々定数と呼ばれます.例:
int a = 100;aはint型変数であり、100は文字面値である.字面値100は右の値にのみ使用でき、左の値には使用できません.
C言語における文字の文字面値は、「a」、「b」などの一対の単一引用符で囲まれた文字である.実際には文字の文字面値は整数の文字面値と同じです.コンパイラは文字のフォント値をすべて整数のフォント値として処理します.
文字変数を定義し、文字のフォント値で初期化します:char ch='a';またはchar ch=97;
int型変数を定義し、文字のフォント値で初期化します.int a='a';いいですよ.
単一引用符で囲まれた複数の文字でchar変数を初期化すると.char ch = 'abcd';C言語はこのような行為を明確に定義していないので、コンパイラは警告を与えますが、間違いは報告されません.だからみんなはそう使わないでください.次にテストしてみましょう.
int main(void)
{
	char ch_1 = 'a';
	char ch_2 = 'abcd';

	return 0;
}
まずVCコンパイラで生成されたアセンブリコードを見てみましょう
cl  /FAsu/c test.cが生成した関連アセンブリコードは以下の通りです:(「abdc」)は規範化されていません.コンパイラは警告を与えます.ここと後ろに関連警告を貼らないようにします.
; 3    : 	char ch_1 = 'a';

	mov	BYTE PTR _ch_1$[ebp], 97		; 00000061H

; 4    : 	char ch_2 = 'abcd';

	mov	BYTE PTR _ch_2$[ebp], 100		; 00000064H
vcコンパイラがchar chに対してないのを見た2='abcd'の処理は'abcd'の最後の文字('d'のascii符号値は100であり、
00000064 Hは16進数の100)
ch_として2の値を入力します.
GCCのこのような状況に対する処理を見てみましょう
gcc-S-fverbose-asm test.cで得られた関連アセンブリコードは以下の通りである.
movb	$97, -1(%ebp)	 #  ch_1
movb	$100, -2(%ebp)	 #  ch_2
は、GCCがこのような単一引用符で複数の文字を参照する場合の処理がvcコンパイラと同じであることを示す.
まとめてみます.
1.文字型と整数型は互いに変換することができる.C言語では文字型が整数型です.
2.文字のフォント値は、単一引用符で囲まれた単一の文字です.
3.一対一の引用符に複数の文字を入れないでください.C言語では定義されていません.コンパイラに完全に依存します.以上の実験から,GCCとVCコンパイラはいずれも最後の文字の字面値しか取っていないことが分かる.文字列の文字面値でもありません(後述します).
もし私が「abcd」という状況でint型変数を初期化したら?
int main(void)
{
	char ch_1 = 'a';
	char ch_2 = 'abcd';
	int a = 'a';
	int b = 'ab';
	int c = 'abcd';

	return 0;
}
VCコンパイラ処理の場合、
cl  /FAsu/c test.cで生成された関連アセンブリコードは以下の通りである.
; 3    : 	char ch_1 = 'a';

	mov	BYTE PTR _ch_1$[ebp], 97		; 00000061H(       00000061H)

; 4    : 	char ch_2 = 'abcd';

	mov	BYTE PTR _ch_2$[ebp], 100		; 00000064H

; 5    : 	int a = 'a';

	mov	DWORD PTR _a$[ebp], 97			; 00000061H

; 6    : 	int b = 'ab';

	mov	DWORD PTR _b$[ebp], 24930		; 00006162H

; 7    : 	int c = 'abcd';

	mov	DWORD PTR _c$[ebp], 1633837924		; 61626364H
GCCコンパイラの処理状況を見てみると、
gcc-S-fverbose-asm test.cで得られた相関アセンブリコード
次のようになります.
movb	$97, -1(%ebp)	 #  ch_1
	movb	$100, -2(%ebp)	 #  ch_2
	movl	$97, -8(%ebp)	 #  a
	movl	$24930, -12(%ebp)	 #  b
	movl	$1633837924, -16(%ebp)	 #  c
上記の結果から、2つのコンパイラは、単一引用符に複数の文字が含まれている場合と同様の処理を行っていることがわかります.最後の文字から自分の必要な値を取り、「abcd」に対してchar型変数は最後の「d」のみを取り、int型変数はabcdのasciiコード値を順番にその値として取ります.
int a='abcde'であれば、それらのascii符号値を組み合わせるとint型(32ビットシステム下と仮定)の表現範囲を超えている.コンパイラはどうしますか?「bdce」を受け取ったのか、それとも間違ったことを報告したのか.実験してみましょう
int main(void)
{
	int ch_1 = 'bcde';
	int ch_2 = 'abcde';//    ch_1 ch_2   

	return 0;
}
はまずVCコンパイラの場合、
cl  /FAsu/c test.c後error C 2015:定数の文字が多すぎます.VCコンパイルはこのような状況を見逃すことはできないようだ.
GCCコンパイラの場合、gcc-S-fverbose-asm test.c後に警告があります.
test.c:3:20: warning: multi-character character constant test.c:4:20: warning: character constant too long for its type
でも通過しました.関連するアセンブリコードは次のとおりです.
movl	$1650680933, -4(%ebp)	 #  ch_1
movl	$1650680933, -8(%ebp)	 #  ch_2
GCCコンパイラは、「abcde」に対して必要なbcdeのみを取得しているように見えます.
上の結び目の後ろにもう1つ追加します
4.異なるコンパイラは、「abcd」のような単一引用符で複数の文字を囲む場合に処理が異なり、このコードは発生しないでください.文字のフォント値は整数のフォント値に変換できますが、コードではこのような動作に依存しないでください.
       これは仁兄のブログを見て感銘を受けただけです.彼が「abcd」という状況を議論しているのを見て、そんなことをする必要はないと思った.しかし、コンパイル時にどのように処理されているかを知りたいです.だから分析してみました.
本文はshimachaoのブログからhttp://blog.csdn.net/shimachao/article/details/8264676転載は出典を明記してください.