GNU C 手册 第十二章

12 常量

常量是通过显式表示所需值来代表特定值的表达式。C 允许数字、字符和字符串使用常量。我们已经在示例中看到了数字和字符串常量。

12.1 整数常量

整数常量由指定值的数字组成,后跟用于指定数据类型的后缀字母(可选)组成。

最简单的整数常量是10十进制数,如5、77和403。十进制常量不能以字符“0”(零)开头,因为那是八进制常量。

通过在开头加上减号可以得到负整数常数的效果。从语法上讲,这是一个算术表达式,而不是常量,但它的行为就像一个真正的常量。

整数常量也可以写成八进制(基数 8)、十六进制(基数 16)或二进制(基数 2)。八进制常量以字符“”(零)开头,后跟任意数量的八进制数字(“”到“”):007

整数常量也可以是八进制(以8为基数)、十六进制(以16为基数)或二进制(以2为基数)。八进制常量以字符“0”(零)开头,后跟任意数量的八进制数字(“0”到“7”):

0 // zero

077 // 63

0403 // 259

学究式地说,常数0是一个八进制常数,但我们可以将其视为十进制;无论哪种方式,它都具有相同的值。

十六进制常量以“0x”(大写或小写)开头,后跟十六进制数字(“0”至“9”,以及大写或小写的“A”至“f”):

0xff // 255

0XA0 // 160

0xffFF // 65535

二进制常量以“0b”(大写或小写)开头,后跟位(每个位由字符“0”或“1”表示):

0b101 // 5

二进制常量是GNU C扩展,不是C标准的一部分。

有时,整数常量后面需要一个空格,以避免与以下标记的词法混淆。

12.2 整数常量数据类型

整型常量的类型通常为int,如果值适合该类型,但以下是完整的规则。整数常数的类型是该序列中能够正确表示值的第一个,

int

unsigned int

long int

unsigned long int

long long int

unsigned long long int

以下规则不排除这一点。

如果常量以“l”或“l”作为后缀,则不包括前两种类型(non-long)。

如果常量以“ll”或“ll”作为后缀,则不包括前四种类型((non-long long)。

如果常量以“u”或“u”作为后缀,则不包括有符号类型。

否则,如果常量为十进制,则排除无符号类型。

以下是后缀的一些示例。

3000000000u // three billion as unsigned int.

0LL // zero as a long long int.

0403l // 259 as a long int.

很少使用整数常量中的后缀。当精确类型很重要时,显式转换会更清晰。

12.3 浮点常量

浮点常量必须具有小数点、十的指数或两者;它们将其与整数常数区分开来。

要表示指数,请写“e”或“e”。指数值如下。它总是写为十进制数;它可以选择以符号开始。指数n表示将常数的值乘以10的n次方。

因此,“1500.0”、“15e2”、“15e+2”、“15.0e2”、“1.5e+3”等。“15e4”和“15000e-1”是1500的六种浮点数写法。它们都是等价的。

以下是更多小数点的示例:

1.0

1000.

3.14159

.05

.0005

对于它们中的每一个,下面是一些用指数编写的等效常量:

1e0, 1.0000e0

100e1, 100e+1, 100E+1, 1e3, 10000e-1

3.14159e0

5e-2, .0005e+2, 5E-2, .0005E2

.05e-2

浮点常量通常具有double类型。您可以通过在末尾添加“f”或“f”来强制它键入float。例如

3.14159f

3.14159e0f

1000.f

100E1F

.0005f

.05e-2f

同样,末尾的“l”或“l”强制常量为类型long double。

您可以在十六进制浮点常量中使用指数,但由于“e”将被解释为十六进制数字,因此字符“p”或“p”(表示“幂”)表示指数。

十六进制浮点常量中的指数是一个可能有符号的十进制整数,指定2的幂(不是10或16)乘以数字。

以下是一些示例:

0xAp2 // 40 in decimal

0xAp-1 // 5 in decimal

0x2.0Bp4 // 16.75 decimal

0xE.2p3 // 121 decimal

0x123.ABCp0 // 291.6708984375 in decimal

0x123.ABCp4 // 4666.734375 in decimal

0x100p-8 // 1

0x10p-4 // 1

0x1p+4 // 16

0x1p+8 // 256

12.4 虚数常量

复数由实部和虚部组成(其中一部分或两部分可能为零)。本节说明如何使用虚值写数字常量。通过将这些添加到普通的数值常量中,我们可以得到复数常量。

编写虚数常量的简单方法是将后缀“i”或“i”,或“j”或“j”,附加到整数或浮点常量。例如,2.5fi具有_Complex float类型,3i具有_ Complex int类型。四个可选后缀字母都是等效的。

写虚常数的另一种方法是将实常数乘以_Complex_I,它表示虚数I。标准C不支持以“I”或“j”作为后缀,因此需要这种笨拙的方法。

要编写一个包含非零实部和非零虚部的复常量,请分别编写这两个常量并添加它们,如下所示:

4.0 + 3.0i

这给出了值4+3i,类型为_Complex double。

这样的和可以包括多个实常量,也可以不包含。同样,它可以包括多个虚常量,也可以不包含。例如:

_Complex double foo, bar, quux;

foo = 2.0i + 4.0 + 3.0i; /* Imaginary part is 5.0. */

bar = 4.0 + 12.0; / Imaginary part is 0.0. */

quux = 3.0i + 15.0i; / Real part is 0.0. */

12.5 无效号码

一些在预处理指令中被视为数字的构造实际上不是有效的数字常量。如果这些构造出现在预处理之外,则它们是错误的。

有时我们需要插入空格来分隔标记,这样它们就不会被组合成单个类似数字的结构。例如,0xE+12是一个预处理数,它不是有效的数值常量,因此是一个语法错误。如果我们想要的是三个标记0xE + 12,我们必须使用这些空格作为分隔符。

12.6 字符常量

字符常量是用单引号编写的,如 中所示。在最简单的情况下, 是常量应表示的单个 ASCII 字符。常量的类型为 ,其值是该字符的字符代码。例如, 表示字母“”的字符代码:97,即。'c'cint'a'a

字符常量用单引号书写,如'c'。在最简单的情况下,c应该表示的单个ASCII字符。常量的类型为int,其值为该字符的字符代码。例如,'a'表示字母“a”的字符代码,即,97。

若要将“'”字符(单引号)作为字符常量,请使用反斜杠(“\”)将其引用。此字符常量看起来像'''。这种以“\”开头的序列称为转义序列。这里的反斜杠字符用作一种转义字符。

要将“”字符(反斜杠)放在字符常量中,请用“”(另一个反斜杠)同样引用它。此字符常量看起来像 。\'\'

要将“\”字符(反斜杠)作为字符常量,请用“\”(另一个反斜杠)。此字符常量看起来像'\'。

以下是表示字符常量中特定字符的所有转义序列。显示的数值是相应的ASCII字符码,以十进制数字表示。

'\a' ⇒ 7       /* alarm, CTRL-g */
'\b' ⇒ 8       /* backspace, BS, CTRL-h */
'	' ⇒ 9       /* tab, TAB, CTRL-i */
'
' ⇒ 10      /* newline, CTRL-j */
'\v' ⇒ 11      /* vertical tab, CTRL-k */
'\f' ⇒ 12      /* formfeed, CTRL-l */
'\r' ⇒ 13      /* carriage return, RET, CTRL-m */
'\e' ⇒ 27      /* escape character, ESC, CTRL-[ */
'\' ⇒ 92      /* backslash character, \ */
'\'' ⇒ 39      /* singlequote character, ' */
'\"' ⇒ 34      /* doublequote character, " */
'\?' ⇒ 63      /* question mark, ? */

“\e”是GNU C扩展;要遵循标准C,使用“\33”。

您还可以将八进制和十六进制字符代码写为“”或“”。十进制在这里不是一个选项,因此八进制代码不需要以''开头。\octalcode\xhexcode0

您还可以将八进制和十六进制字符代码编写为“\octalcode”或“\xhexcode”。十进制在这里不是一个选项,因此八进制代码不需要以“0”开头。

字符常量的值具有int类型。但是,字符代码最初被视为char值,然后转换为int。如果字符代码大于127(八进制中的0177),则在char类型为8位长且有符号的平台上,结果int可能为负数。

12.7 字符串常量

字符串常量表示一系列字符。它以“”开头,以“”结尾;介于两者之间的是字符串的内容。在内容中引用特殊字符(如“”,“”和换行符)在字符串常量中与字符常量一样有效。在字符串常量中,“”不需要用引号引起来。"""'

字符串常量表示一系列字符。它以“开头,以”结尾;中间是字符串的内容。在字符串中引用特殊字符,如 '、“\”和换行符与在字符常量中一样。在字符串常数中,不需要引用“'”。

字符串常量定义一个字符数组,其中包含指定的字符,后跟空字符(代码0)。使用字符串常量相当于使用包含这些内容的数组的名称。在简单情况下,字符串常量的长度(以字节为单位)比写入其中的字符数大 1。

与C中的任何数组一样,在表达式中使用字符串常量会将数组转换为指向数组第一个元素的指针。该指针将具有char *类型,因为它指向char类型的元素。char *是指针类型的类型指示符示例。该类型通常用于字符串,而不仅仅是程序中表示为常量的字符串。

因此,字符串常量“Foo!”几乎相当于这样声明一个数组

char string_array_1[] = {'F', 'o', 'o', '!', '\0' };

然后在程序中使用string_ array_。然而,有两个区别:

  • 字符串常量不定义数组的名称。
  • 字符串常量可能存储在内存的只读区域中。

字符串常量的文本中不允许使用换行符。此禁止的动机是捕捉省略”的错误。要在常量字符串中放置换行符,请在字符串常量中将其写为“ ”。

字符串常量内的源代码中的实际空字符会导致警告。若要在字符串常量的中间放置空字符,使用“\0”或“\000”。

连续的字符串常量被有效地串联。因此

"Fo" "o!" is equivalent to "Foo!"

这对于编写包含多行的字符串很有用,如下所示:

"This message is so long that it needs more than "

"a single line of text. C does not allow a newline "

"to represent itself in a string constant, so we have to "

"write to put it in the string. For readability of "

"the source code, it is advisable to put line breaks in "

"the source where they occur in the contents of the "

"constant. "

反斜杠和换行的序列在C程序中的任何位置都被忽略,并且包括在字符串常量中。因此,您可以这样编写多行字符串常量:

"This is another way to put newlines in a string constant
and break the line after them in the source code."

但是,串联是执行此操作的推荐方法。

你也可以像这样写反常的字符串常量,

"Fo
o!"

但不要这样做 - 改为这样:

"Foo!"

请注意避免将字符串常量传递给修改其接收的字符串的函数。存储字符串常量的存储器可能是只读的,这将导致通常终止函数的致命信号(请参阅信号。更糟糕的是,内存可能不是只读的。然后,该函数可能会修改字符串常量,从而破坏其他字符串常量的内容,这些字符串常量应该包含相同的值并由编译器统一。SIGSEGV

小心避免将字符串常量传递给那些会修改其接收到的字符串的函数。存储字符串常量的内存可能是只读的,这将导致致命的SIGSEGV信号,该信号通常会终止函数(请参阅信号)。更糟糕的是,内存可能不是只读的。然后函数可能会修改字符串常量,从而破坏其他字符串常量的内容,这些字符串常量本应包含相同的值,并由编译器统一成一体。

12.8 UTF-8 字符串常量

紧挨着字符串常量之前写入“u8”,中间没有空格,意味着以UTF-8编码将该字符串表示为字节序列。UTF-8使用单个字节来描述ASCII字符,并将非ASCII Unicode字符(代码128及以上)表示为多字节序列。以下是UTF-8常量的示例:

u8"A cónstàñt" 该常量占用13字节加上终止的null,因为每个重音字母都是一个双字节序列。

从概念上讲,将普通字符串与UTF-8字符串连接会生成另一个UTF-8字符串。但是,如果普通字符串包含字符代码128及更高,则不能依赖结果。

12.9 Unicode字符码

可以使用转义序列为单个字符常量指定 Unicode 字符或作为字符串常量的一部分(请参阅字符串常量)。将“”转义序列与 16 位十六进制 Unicode 字符代码一起使用。如果代码值对于 16 位来说太大,请使用带有 32 位十六进制 Unicode 字符代码的“”转义序列。(这些代码称为通用字符名称。例如\u\U

可以使用转义序列为单个字符常量或作为字符串常量的一部分指定Unicode字符。将“\u”转义序列与16位十六进制Unicode字符代码一起使用。如果代码值对于16位来说太大,请使用32位十六进制Unicode字符代码的“\U”转义序列。例如,

水 /* 16-bit code (UTF-16) */

\U0010ABCD / 32-bit code (UTF-32) */

使用这些的一种方法是使用UTF-8字符串常量。例如

u8"fóó 水 \U0010ABCD"

您还可以在宽字符常量中使用它们,如下所示:

u'水' /* 16-bit code */

U'\U0010ABCD' / 32-bit code */

和宽字符串常量,如下所示:

u"水氳" /* 16-bit code */

U"\U0010ABCD" / 32-bit code */

D800到DFFF范围内的代码在Unicode中无效。小于00A0的代码也是被禁止的,除了0024 、0040和0060外, 这些字符实际上是ASCII控制字符,您可以使用其他转义序列指定它们。

12.10 宽字符常量

宽字符常量表示字符代码超过8位的字符。这是一个我们需要记录的模糊功能,但您可能永远不会使用它。如果你只是在学习C语言,你不妨跳过这一节。

原始的C宽字符常量看起来像“L”(大写!)紧接着一个普通字符常量(没有中间空格)。其数据类型为wchar_t,是定义在stddef.h中的,其中一个标准整数类型的别名。根据平台的不同,它可以是16位或32位。如果是16位,这些字符常量使用UTF-16形式的Unicode;如果是32位,则为UTF-32。

还有一些Unicode宽字符常量,它们显式指定宽度。这些常量以“u”或“U”而不是“L”开头。“u”指定16位Unicode宽字符常量,“U”指定32位Unicode宽度字符常量。它们的类型分别为char16_t和char32_t;它们在头文件uchar.h中声明。这些字符常量也是有效的,即使没有#include uchar.h,但如果不包括它来声明这些类型名称,它们的某些使用可能会很不方便。

宽字符常量中表示的字符可以是普通ASCII字符。L'a',u'a'和u'a'都是有效的,它们都等于'a'。

在所有三种宽字符常量中,可以在常量本身中写入非ASCII Unicode字符;常量的值是字符的Unicode字符代码。或者可以使用转义序列指定Unicode字符。

12.11 宽字符串常量

宽字符串常量表示16位或32位字符的数组。它们很少使用;如果你只是在学习C语言,你不妨跳过这一节。

有三种宽字符串常量,它们在用于字符串中每个字符的数据类型上有所不同。每个宽字符串常量相当于一个整数数组,但这些整数的数据类型取决于宽字符串的类型。在表达式中使用常量会将数组转换为指向其第一个元素的指针,就像C中的数组一样。对于每种宽字符串常量,我们在下面说明该指针的类型。

char16_t

这是一个16位Unicode宽字符串常量:每个元素都是一个类型为char16_t的16位Unicode字符代码,因此该字符串的指针类型为char16_t*。(这是一个类型指示符;参见指针类型指示符。)常量被写为“u”(必须小写),后跟(没有中间空格)一个字符串常量,使用通常的语法。

char32_t

这是一个32位Unicode宽字符串常量:每个元素都是32位的Unicode字符代码,字符串的类型为char32_t*。它写为“U”(必须是大写),后面(没有中间空格)是一个字符串常量,使用通常的语法。

wchar_t

这是宽字符串常量的原始类型。它被写为“L”(必须是大写),后面(没有中间空格)是一个具有通常语法的字符串常量,字符串的类型为wchar_t*。
数据类型wchar_t的宽度取决于目标平台,这使得这种宽字符串与较新类型相比没有多少用处。

char16_t和char32_t在头文件uchar.h中声明。wchar_t声明在stddef.h中。

相同类型的连续宽字符串常量连接在一起,就像普通字符串常量一样。宽字符串常量与普通字符串常量连接会产生宽字符串常量。不能连接两个不同类型的宽字符串常量。也不能将宽字符串常量(任何类型)与UTF-8字符串常量连接起来。

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章