多くのC言語やC++の入門書の最初のほうには、変数名や関数名などの識別子に使える文字として、アルファベットの大文字・小文字、数字、下線(アンダースコア、アンダーバー)だけが使えると書いています。確かに初期のC言語の規格はそうでしたし、標準化前のC++もそうでした。しかし、現在の標準規格はそうはなっていません。

例えばC言語の場合、識別子の構文は次のようになっています。

identifier:
identifier-nondigit
identifier identifier-nondigit
identifier digit

identifier-nondigit:
nondigit
universal-character-name

other implementation-defined characters

nondigit: one of
_ a b c d e f g h i j k l m
n o p q r s t u v w x y z
A B C D E F G H I J K L M
N O P Q R S T U V W X Y Z

digit: one of
0 1 2 3 4 5 6 7 8 9

これはC99以降、C17に至るまで同じです。C++でも、other implementation-defined charactersが含まれない点を除けば実質的に同じです。つまり、ここで注目すべきなのは、universal-character-nameというのが含まれている点です。universal-character-name は、日本語訳すなわちJIS X3010およびJIS X3014では「国際文字名」と呼んでいます。

国際文字名というのは、ISO 10646文字集合の文字を16進数で直接記述してしまおうという仕様です。例えば、「変数」という名前の変数名を使うには\u5909\u6570のように、\uに続けて4桁の16進数を記述することになります。16ビットで収まらない場合には、\U00123456 のように、\Uに続けて8桁の16進数を記述することもできます。あるいはサロゲートペアを使って表現することもできます。

使える文字が増えたのはよいことですが、これだけでは何とも非人間的な仕様です。できれば、普通に漢字かな混じりで書きたいところです。C++では、翻訳フェーズ 1、すなわち三つ組表示(三文字表記)を対応する 1文字に置き換えるのと同じ段階で、基本ソース文字集合にない文字を対応する国際文字名に変換することが明記されています。C言語の規格では、ちょっと不明瞭です。

現実の処理系を見ていくと、Visual C+はかなり前から識別子にUnicodeを使えていました。それが国際文字名に置換されるかどうかはともかく、実質的には同じように使えていました。Clangも識別子に多バイト文字を使えば国際文字名に置換してくれます。macOS上のXcodeで経験した方もおられるかもしれません。GCCは-fextended-identifiersを指定すれば16進数の国際文字名は使えましたが、長い間多バイト文字を識別子に使うことはできませんでした。しかし、最近のバージョンではソースファイルをUTF-8で記述すれば識別子に多バイト文字を使えるようになっています。

このように、主要な処理系では識別子に多バイト文字を使えるようになっていますが、マイコン向けの処理系などではまだ対応していないものも少なくないかと思います。そういった処理系を使う限りにおいては、識別子に使える文字は英数字と下線のみという考え方は間違っていないかもしれません。