【C/C++】美元能做英镑却做不了的事 - 在标识符中使用通用字符
下面这段代码:
这里我们使用符号“$”作为变量名,熟悉C++的同学知道,“$”可作为标识符是后面标准加上的事情,不过在此之前已经有很多编译器内部支持了,例如gcc的选项:
试试把变量名换成英镑:
编译报错:
很多资料会说,标识符只能是字母下划线开头,后面跟字母下划线数字,当然上面我们知道C++里面“$”被扩展进来,按这个说法其他字符当然不行
然而换成用汉字和图画符号试试看:
那么这是编译器的implementation defined吗?就这个例子来说,部分是,部分不是
从标识符的语法定义来说,至少在C99和C++11起,就允许使用通用字符集(就理解为unicode字符集)的部分字符,所以上面用“猫”和“🐱”都是标准认定合法的
但是,允许使用这些字符不代表代码里面一定可以出现这些字符,因为关于代码的组织形式,还规定了基础源字符集,共96个:
就是说,如果编译器自己不做扩展的话,原则上一个代码文件只能用这96个字符进行书写,那既然还规定了标识符可以用部分unicode字符,若要用,该怎么书写呢?
答案是用转义:
转义用“\uHHHH”或“\UHHHHHHHH”的形式,十六进制不区分大小写,直接书写在代码的对应位置即可,当然,我这里的gcc是支持直接书写通用字符的,所以在上面代码中可以转义或原始字符混用,即“\u732B”、“\U0000732b”和“猫”三种写法都是通用的,在编译器看来没有区别
实际上这里用“编译器”并非很严谨,因为从规范来说,通用字符的处理是在编译之前,甚至是在预处理之前,在读入源码文件后就先进行了
可以只调用预处理器,输出一下对上面代码的预处理结果(main函数部分):
可以看到,在正式编译之前,字符就已经被处理了,gcc的办法是统一转成8位16进制的\U形式,而clang对于汉字则原样保留,对于0xFFFF以上的unicode则使用\U形式
因此,有人说\u和\U转义是字符串中的转义字符,这并不正确,处理它们的时候还没字符串什么事情,上面的示例代码也和字符串毫无关系,而事实上字符串的转义序列定义也没有提到\u和\U
一般的资料会说,C和C++的编译过程是先预处理再编译,但在这两者之外,编译器还是有一些事情需要进行,整个步骤统称“翻译阶段”,其中涉及到语法和代码处理的不少细节,后续我们会继续分享其中的一些问题
回到开头的问题,英镑符号也是一个unicode字符,但为何就报错了呢?因为并非所有unicode字符都可以用来组成标识符,英镑恰巧就被排除在外了
附C++11中定义的可以用来做标识符的字符范围:
常用汉字的范围是4E00-9FA5,可安全使用
没用的知识又增加了~~~