web-dev-qa-db-ja.com

このソースコードはCで文字列を切り替えています。どのようにそれを行いますか?

私はいくつかのエミュレータコードを読んでいて、本当に奇妙なことに反論しました:

switch (reg){
    case 'eax':
    /* and so on*/
}

これはどのように可能ですか?整数型ではswitchしかできないと思いました。マクロの策略はありますか?

105
Ian Colton

(「マクロトリック」の部分に答えることができるのは、コードを貼り付けない限りです。ただし、マクロが機能する場所はあまりありません。正式にはキーワードを再定義することはできません;その実行時の動作は未定義です。

プログラムを読みやすくするために、機知に富んだ開発者は、実装定義の動作を利用しています。 'eax'not文字列ですが、複数文字定数です。 eaxを囲む一重引用符に注意してください。ほとんどの場合、その文字の組み合わせに固有のintが与えられています。 (多くの場合、各文字は32ビットintで8ビットを占有します)。そして、誰もがswitchintにできることを知っています!

最後に、標準参照:

C99標準には次のように記載されています。

6.4.4.4p10:「複数の文字(例: 'ab')を含む整数文字定数の値、またはシングルバイト実行文字にマッピングされない文字またはエスケープシーケンスを含む整数定数の値は、実装定義です。 」

145
Bathsheba

C標準(6.8.4.2 switchステートメント)に準拠

3 各ケースラベルの式は整数定数式でなければならない ...

および(6.6定数式)

6 整数定数式は整数型であり、整数定数、列挙定数、文字定数、結果が整数定数である式のサイズ、および浮動定数であるオペランドのみを持つそれはキャストの直接のオペランドです。整数定数式のキャスト演算子は、算術型を整数型に変換しますが、sizeof演算子のオペランドの一部を除きます。

'eax'とは何ですか?

C標準(6.4.4.4文字定数)

2整数文字定数は、単一引用符で囲まれた1つまたは複数のマルチバイト文字のシーケンスです(「x」など)。

したがって、'eax'は、同じセクションの段落10による整数文字定数です。

  1. ...複数の文字(例: 'ab')を含む整数文字定数の値、またはシングルバイト実行文字にマップされない文字またはエスケープシーケンスを含む整数文字定数の値は、実装定義です。

したがって、最初に言及した引用によれば、ケースラベルとして使用できる整数定数式のオペランドになります。

(一重引用符で囲まれた)文字定数の型はintであり、文字配列の型を持つ文字列リテラル(二重引用符で囲まれた文字のシーケンス)とは異なることに注意してください。

44

他の人が言ったように、これはint定数であり、その実際の値は実装定義です。

コードの残りの部分は次のように見えると思います

if (SOMETHING)
    reg='eax';
...
switch (reg){
    case 'eax':
    /* and so on*/
}

最初の部分の「eax」が2番目の部分の「eax」と同じ値を持っていることを確認できるので、すべてうまくいきますか? ... 違う。

@Davislorのコメントには、「eax」の可能な値がいくつかリストされています。

... 0x650x6561780x656178000x7861650x6165など

最初の潜在的な値に注目してください。それは'e'であり、他の2文字を無視します。問題は、プログラムがおそらく'eax''ebx'などを使用していることです。これらすべての定数が'e'と同じ値を持つ場合、最終的には

switch (reg){
    case 'e':
       ...
    case 'e':
       ...
    ...
}

これは見た目がよくありませんか?

「実装定義」の良いところは、プログラマがコンパイラのドキュメントをチェックして、これらの定数で適切な処理を実行できるかどうかを確認できることです。もしそうなら、家に無料。

悪い点は、他の貧しい人がコードを受け取り、他のコンパイラを使用してそれをコンパイルしようとする可能性があることです。インスタントコンパイルエラー。このプログラムは移植性がありません。

@zwolがコメントで指摘したように、状況は思ったほど悪くはなく、悪い場合にはコードはコンパイルされません。これにより、少なくとも問題の正確なファイル名と行番号がわかります。それでも、動作するプログラムはありません。

12
Stig Hemmer

コードフラグメントは、multi-character character constantと呼ばれる歴史的な奇妙さを使用します。これは、multi-charsとも呼ばれます。

'eax'は、実装で定義された値を持つ整数定数です。

以下に、マルチ文字とその使用方法に関する興味深いページを示しますが、使用すべきではありません。

http://www.zipcon.net/~swhite/docs/computers/languages/c_multi-char_const.html


バックミラーをさらに振り返ると、古き良き時代のデニス・リッチーによるオリジナルのCマニュアル( https://www.bell-labs.com/usr/dmr/www/cman.pdf )指定された文字定数。

2.3.2文字定数

文字定数は、単一引用符で囲まれた1つまたは2つの文字「'」です。文字定数内では、単一引用符の前にバックスラッシュ「\」を付ける必要があります。特定の非グラフィック文字、および「 '\」自体は​​、次の表に従ってエスケープできます。

    BS \b
    NL \n
    CR \r
    HT \t
    ddd \ddd
    \ \\

エスケープ「 '\ddd」は、バックスラッシュとそれに続く1、2、または3桁の8進数で構成され、目的の文字の値を指定するために使用されます。この構造の特殊なケースは、「\0」(数字が続かない)で、ヌル文字を示します。

文字定数は整数とまったく同じように動作します(特に、文字型のオブジェクトとは異なります)。 PDP-11のアドレス指定構造に準拠して、長さ1の文字定数には、特定の文字のコードが下位バイトにあり、0が上位バイトにあります。長さ2の文字定数には、下位バイトの最初の文字のコードと、上位バイトの2番目の文字のコードがあります。複数の文字を含む文字定数は本質的にマシンに依存するため、使用しないでください。

最後のフレーズは、この奇妙な構造について覚えておく必要があるすべてです:複数の文字を持つ文字定数は、本質的にマシン依存であり、避ける必要があります。

1
chqrlie