最新のC ++コンパイラは識別子でUnicodeをサポートしていることが判明

80年代初期にJermainとStableプログラミングでプログラミングすることを学んだ人にとっては、ワイルドに見えます。 おそらく、Straustrupの初期版からC ++を学んだ人たちにとっても。 それはかなり前のことでした。 おそらく次世代のために、私が説明しようとしていることは、野asさのように思えます。 それでも、このトピックはそれほど空ではありません。 老人のうなり声を聞くのが面倒ではない人は、猫の下に行きます。



今日の言語標準では、「a-z、A-Z、_」の文字は識別子のどこにでも使用できます。 文字「0-9」は、単語の先頭以外のあらゆる場所にあります。 他の兆候はそこに記載されていません。 MicrosoftはVisualStudioでドル記号「$」を文字として分類し、コンパイラーがまだ区別する名前の最大長は2048文字であることも規定しています。 さらに可能ですが、余分な文字は無視されます。 詳細については、 対応するMSDNページ参照してください。



これをすべて説明することになった問題。 不要なものをすべて削除すると、次のようになります。



void some(){ int c(0); ++; } //error C2065: '' : undeclared identifier
      
      





2番目の文字「c」はロシア文字esであることがわかります。 彼女がそこに現れたのは驚くことではありません;キーボードでは、これらの二重文字が1つのキーを占有します。 レイアウトを時間通りに切り替えなかっただけです。



コンパイラがこのシンボルを、宣言されていないにもかかわらず有効なC ++言語識別子として使用したことは驚くべきことでした。 より予想されるエラーは、「無効なトークン」などです。 これが何を意味するのかを理解するために、コンパイラをもう少し拷問します。 錯視を排除するために、「c」の代わりに、より認識可能なロシア語の文字を追加しました。 このように、例えば:



 void some(){ int (0); ++; } //OK
      
      





動作します。



さらに進んで、さらに多くの新しい標識を追加します。 この実験では、Unicodeのほぼ全体が「許可された」文字セットに含まれていることが示されています。これは、言語標準で他のものに予約されていないものすべてです。 Google翻訳で取得できる言語の兆候。 本格的な実験を行うには、ファイルの先頭にBOMを含めることを忘れずに、ソースをUTF-8形式で保存する必要があります。 ロシア文字の場合、これはできません。



たとえば、このようなプログラムはエラーなしでコンパイルおよび実行されます。



 #include <stdio.h> #include <math.h> #define 前 for #define 整数 int #define ダブル double #define 虚しい void #define 刷るフ printf #define サイン sin #define フフラッシュ fflush虚しい それをやる(){前(整数 私 = 0; 私 < 100; ++私){ダブル x = 2 * 3.1415926 * ダブル(私)/100;刷るフ("\n%g;%g", x, サイン(x)); }フフラッシュ(stdout); }整数 _tmain(整数argc, _TCHAR* argv[]) {それをやる(); return 0; }
      
      





どうやら、これが正しいシンボルであるかどうかの評価はほとんど偶然に得られます。 Windowsの場合、「どのUnicode文字が文字と見なされるか」という質問に対する視点は、Windows APIの関数によって決定されます



 BOOL IsCharAlpha(TCHAR ch);
      
      





この関数の作成者は、当然、対応する言語の話者が単語を形作るすべての文字に起因します。 そして、コンパイラ開発者は、そのような関数を場違いに使用しないようです。



簡単なテスト例を作成します。



 #include "stdafx.h" #include <windows.h> #include <stdio.h> #include <conio.h> int _tmain(int argc, _TCHAR* argv[]){ TCHAR  = ''; // 8-bit "", false BOOL is_letter = IsCharAlpha(); printf("letter = %d\n", int(is_letter)); getch(); return 0; }
      
      





TCHARへの変換時にコード0xFEの8ビットキリル文字記号「u」は0xFFFEに変わります。これは、文字のない予約済みのユニコード領域です。 予想されるfalseを取得します。 その他の文字のうち、句読点、擬似グラフィック文字、および何らかの理由で点字は否定的な結果を示します。 残りは文字と見なされます。 テストされたコードの短いリストは次のとおりです。



 // TCHAR  = 0x044E;// UTF-16 "", true // TCHAR  = 0x00E1;// UTF-16 latin "small a with acute" letter, true // TCHAR  = 0x0633;// UTF-16 arabic "sin" letter, true // TCHAR  = 0x09A2;// UTF-16 bengalic "ddha" letter, true // TCHAR  = 0x0060;// UTF-16 "grave accent", false // TCHAR  = 0x00BD;// UTF-16 "one half ligature", false // TCHAR  = 0x27F5;// UTF-16 "long lefwards area", false
      
      





誰かが新しい機会に満足するかもしれません。 しかし、私はしません。 実際のプログラマーの作業では、このような変数名の拡張セットが必要になるのではないかと非常に疑っています。 そして、これがエラーの原因であるという事実は、多くの人が確認する機会がありました。 このようなエラーを診断するために、16進エディタでテキストを分析する必要がある場合があることは特に不快です(2文字の場合)。 もちろん、MSVSも例外ではありません。



一般に、現在のコンパイラのこの機能について知る必要があります。 また、「奇妙なエラー」が表示された場合は、正しいレイアウトで問題があることが判明した識別子をもう一度入力することをお勧めします。



しかし、何かのために、それは役に立つことができますか? 私はこの問題について長い間考えていましたが、それでも思いつきました。 ここ。 むかしむかし、アルゴル語の独特なロシア語版が学生を教えるために使われました。 このような言語は、Microsoft C ++コンパイラを使用して簡単にエミュレートできるようになりました。 たぶん誰かがノスタルジーを望んでいますか?



このようなもの:



 #define  { #define  if( #define  ) #define  else #define  }
      
      





終わり。



All Articles