词法元素(八)
六、标点符号
标点符号(punctuators)是具有独立语法和语义的符号。根据上下文,标点符号可以指示执行某个操作(该操作可能生成一个值或者函数指示符,也可能产生副作用,或者它们的某种组合。),这种情况下标点符号也称为运算符(operator)。运算符作用实体称为操作数(operand)。C语言运算符包含标点符号,但不限于标点符号,例如:sizeof、alignof等运算符。
C语言中标点符号包括:
[ ] ( ) { } . -> ++ -- & * + - ~ !
/ % << >> < > <= >= == != ^ | && || ? : ; ... ::
= *= /= %= += -= <<= >>= &= ^= |= , # ##
<: :> <% %> %: %:%:
其中::是ISO/IEC 9899:2024标准新增标点符号;最后一行标点符号为双字符(digraphs),其对应字符如下表所示:
| 标点符号 | <: | :> | <% | %> | %: | %:%: |
| 对应字符 | [ | ] | { | } | # | ## |
如果在字符常量或者字符串字面量中,上述字符不会被解释成双字符;例如:
puts("<:"); //将输出<:。
字符串化的情况除外,双字符和对应字符可以互换。
#define PRINT(n) printf(#n " = %d\n", n) ... int arr[] = {1, 3, 5}; PRINT(arr[1]); //输出arr[1] = 3。 PRINT(arr<:1:>); //输出arr<:1:> = 3。
#n将n字符串化;语句PRINT(arr[1]);等价于语句printf("arr[1]" " = %d\n", arr[1]);;语句PRINT(arr<:1:>);等价于语句printf("arr<:1:>" " = %d\n", arr[1]);。
七、头文件名
C语言头文件名(header names)具有以下两种形式:
< h-char-sequence > " q-char-sequence "
h-char-sequence序列中的字符可以是源字符集中除换行符和>字符外的任何字符;但如果在h-char-sequence序列中出现'、\、"、//、/*字符,其行为是未定义的。q-char-sequence序列中的字符可以是源字符集中除换行符和"字符外的任何字符;但如果在q-char-sequence序列中出现'、\、//、/*字符,其行为是未定义的。因此类似转义序列的字符序列会导致未定义行为。
文件名中的序列以实现定义的方式映射到头文件名或者外部源文件名。头文件名预处理标记仅在#include和#embed预处理指令、__has_include和__has_embed表达式、以及#pragma指令中的实现定义位置被识别,例如:在#pragma指令中使用头文件名预处理标记。
使用#include指令包含头文件存在以下两种形式:
① #include <h-char-sequence> new-line
其中new-line为换行符。执行该指令时,先在实现定义的位置搜索由h-char-sequence序列标识的头文件(以Unix系统为例,将搜索目录/usr/include。);然后用该头文件的内容替换该指令。这种形式用于包含标准库头文件以及实现版本提供的头文件,例如:
#include <stdio.h>
② #include "q-char-sequence" new-line
执行该指令时,先在实现定义的位置(该位置通常为当前目录。)搜索由q-char-sequence序列标识的源文件;然后用源文件的内容替换该指令。如果实现不支持此类搜索或者搜索失败,该指令像读取以下指令一样重新处理。
#include <h-char-sequence> new-line
h-char-sequence序列与原指令中q-char-sequence序列具有相同的字符;如果q-char-sequence序列中存在>字符,h-char-sequence序列也将存在>字符。
这种形式通常用于程序员编写的文件,例如:
#include "myHeader.h"