算术类型

来自cppreference.com
< c‎ | language


(可参阅类型,以获得类型系统综述,及 C 库提供的类型相关工具列表。)

目录

布尔类型

  • _Bool(亦可作为宏 bool 使用)(C23 前)bool(C23 起) — 类型,足以保有两个值之一:10(亦可作为宏 truefalse 使用)(C23 前)truefalse(C23 起)

注意,到 _Bool(C23 前)bool(C23 起)转换与到其他整数类型的转换不同:(bool)0.5 求值为 true,然而 (int)0.5 求值为 0

(C99 起)

[编辑] 字符类型

  • signed char — 用作有符号字符类型。
  • unsigned char — 用作无符号字符类型。亦可用于查看对象表示(无修饰内存)。
  • char — 用于字符类型。 与 signed charunsigned char 等价(具体等价于哪个是实现定义的,并且可以通过编译器命令行开关控制),但 char 是独立的类型,与 signed charunsigned char 都不相同。

注意:标准亦定义了 typedefwchar_tchar16_tchar32_t(C11 起) 以表示宽字符,以及表示 UTF-8 字符的 char8_t(C23 起)

[编辑] 整数类型

  • short int (亦可用作 short,可以用关键词 signed
  • unsigned short int (亦可用作 unsigned short
  • int (亦可用作 signed int
这是平台的最理想整数类型,保证至少为 16 位。当前大多数平台使用 32 位(见后述的数据模型)。
  • unsigned int (亦可用作 unsigned),int 的无符号对应者,实现模算术。适合位操作。
  • long int (亦可用作 long
  • unsigned long int (亦可用作 unsigned long
  • long long int (亦可用作 long long
  • unsigned long long int (亦可用作 unsigned long long
(C99 起)
  • _BitInt(n)(亦可用作 signed _BitInt(n)),位精确的有符号整数类型(其中 n 由代表精确宽度(包括符号位)的整数常量表达式替换,它不能大于 <limits.h> 中的 BITINT_MAXWIDTH
  • unsigned _BitInt(n),位精确的无符号整数类型(其中 n 由代表精确宽度的整数常量表达式替换,它不能大于 <limits.h> 中的 BITINT_MAXWIDTH
(C23 起)

注意:同所有类型说明符,允许任意顺序: unsigned long long intlong int unsigned long 指名同一类型。

下表总结所有可用的整数类型及其属性:

类型说明符 等价类型 数据模型中的位宽
C 标准 LP32 ILP32 LLP64 LP64
char
char 至少
8
8 8 8 8
signed char
signed char
unsigned char
unsigned char
short
short int 至少
16
16 16 16 16
short int
signed short
signed short int
unsigned short
unsigned short int
unsigned short int
int
int 至少
16
16 32 32 32
signed
signed int
unsigned
unsigned int
unsigned int
long
long int 至少
32
32 32 32 64
long int
signed long
signed long int
unsigned long
unsigned long int
unsigned long int
long long
long long int
(C99)
至少
64
64 64 64 64
long long int
signed long long
signed long long int
unsigned long long
unsigned long long int
(C99)
unsigned long long int

除了最小位数, C 标准还保证

1 == sizeof(char) sizeof(short) sizeof(int) sizeof(long) sizeof(long long)

注意:所允许的极端情形为,字节大小为 64 位,所有类型(包括 char)均为 64 位宽,而 sizeof 对每个整数类型都返回 1。

注意:整数算术的定义对于有符号数和无符号数不同。见算数运算符,尤其是整数溢出

[编辑] 数据模型

每个实现关于基础类型的大小选择被统称为数据模型。有四种广为接受的数据模型:

32 位系统:

  • LP322/4/4int 为 16 位,long 与指针为 32 位)
  • Win16 API
  • ILP324/4/4intlong 及指针为 32 位);
  • Win32 API
  • Unix 及类 Unix 系统(Linux、Mac OS X)

64 位系统:

  • LLP644/4/8intlong 为 32 位,指针为 64 位)
  • Win64 API
  • LP644/8/8int 为 32 位,long 及指针为 64 位)
  • Unix 与类 Unix 系统(Linux、Mac OS X)

其他数据模型非常罕见。例如,ILP648/8/8intlong 及指针均为 64 位)仅出现于某些早期 64 位 Unix 系统(例如 Cray 上的 Unicos)。

注意从 C99 开始可从 <stdint.h> 中使用准确宽度的整数。

[编辑] 实浮点数类型

C 拥有三或六(C23 起)种表示实浮点数的类型:

  • float — 单精度浮点数类型。若支持则匹配 IEEE-754 binary32 格式
  • double — 双精度浮点数类型。若支持则匹配 IEEE-754 binary64 格式
  • long double — 扩展精度浮点数类型。若支持则匹配 IEEE-754 binary128 格式,否则若支持则匹配 IEEE-754 binary64 扩展格式,否则匹配某种精度优于 binary64 而值域至少和 binary64 一样好的非 IEEE-754 扩展浮点数格式,否则匹配 IEEE-754 binary64 格式。
    • 一些 HP-UX、 SPARC、 MIPS、 ARM64 和 z/OS 实现使用 binary128 格式。
    • 最知名的 IEEE-754 binary64 扩展格式是 80 位 x87 扩展精度格式。许多 x86 和 x86-64 实现使用它(一个典型的例外是 MSVC ,它将 long double 实现为与 double 相同的格式,即 binary64)。
若实现预定义宏常量 __STDC_IEC_60559_DFP__ ,则下列十进制浮点数类型亦得到支持。
否则,不支持这些十进制浮点数类型。
(C23 起)

浮点数类型可以支持特殊值:

  • 无穷大(正与负),见 INFINITY
  • 负零-0.0。它与正零比较相等,但对于某些算术运算有意义(例如 1.0/0.0 == INFINITY,但 1.0 / -0.0 == -INFINITY)。
  • 非数(NaN),它与任何值比较不相等(包括其自身)。有多种位模式表示 NaN,见 nanNAN。注意 C 对(IEEE-754 所指定的)NaN 信号不作任何留意,并安静处理所有 NaN。

实浮点数可与算术运算符 + - / * 和来自 <math.h> 的大量数学函数一同使用。内建运算符和库函数都可能引发浮点数异常,并以 math_errhandling 中描述的方式设置 errno

浮点数表达式可拥有大于其类型所指示的范围和精度,见 FLT_EVAL_METHOD赋值return转型强制将范围和精度变成声明类型所关联者。

浮点数表达式亦可被缩略,即仿佛中间值拥有无限范围和精度一般计算,见 #pragma STDC FP_CONTRACT

一些浮点数上的运算会受到浮点数环境的影响,或修改它(最值得注意的是舍入方向)。

实浮点数类型与整数、复数和虚数类型间的隐式转换有定义。

附加细节、极限和浮点数类型属性见浮点数类型极限<math.h> 库。

复浮点数类型

复浮点数类型模仿数学的复数,即可以写成一个实数与一个实数乘虚数单位的和的数: a + bi

三种复数类型是

注意:同所有类型说明符,允许任意顺序:long double complexcomplex long double,甚至 double complex long 都指名同一类型。

#include <complex.h>
#include <stdio.h>
 
int main(void)
{
    double complex z = 1 + 2*I;
    z = 1 / z;
    printf("1/(1.0+2.0i) = %.1f%+.1fi\n", creal(z), cimag(z));
}

输出:

1/(1.0+2.0i) = 0.2-0.4i

若实现定义了宏常量 __STDC_NO_COMPLEX__ ,则不提供复数类型(还有库头文件 <complex.h>)。

(C11 起)

每个复数类型均与拥有两个对应实数类型(float 之于 float complexdouble 之于 double complexlong double 之于 long double complex)元素的数组具有相同的对象表示对齐要求。数组第一元素保有实部,而第二个元素保有虚部。

float a[4] = {1, 2, 3, 4};
float complex z1, z2;
memcpy(&z1, a, sizeof z1); // z1 成为 1.0 + 2.0i
memcpy(&z2, a+2, sizeof z2); // z2 成为 3.0 + 4.0i

复数可用于算术运算符 + - */ 使用,并可与虚数和实数混合运算。<complex.h> 中为复数定义了许多数学函数。内建运算符和库函数都可能引发浮点数异常,并按 math_errhandling 中描述的方式设置 errno

复数类型中不定义自增和自减。

复数类型中不定义关系运算符(没有“小于”的记号)。

隐式转换定义于复数类型和其他算术类型。

为支持复数算术的一个无限模型, C 认可任何至少有一个无限部分的复数值为无穷大,即使另一部分是 NaN ,保证所有运算符和函数忠实于无穷大的基本属性,并提供 cproj 以映射所有无穷大到标准的一(准确规则见算术运算符)。

#include <complex.h>
#include <math.h>
#include <stdio.h>
 
int main(void)
{
    double complex z = (1 + 0*I) * (INFINITY + I*INFINITY);
//  教科书公式会给出
//  (1+i0)(∞+i∞) ⇒ (1×∞ – 0×∞) + i(0×∞+1×∞) ⇒ NaN + I*NaN
//  但 C 给出复无穷大
    printf("%f%+f*i\n", creal(z), cimag(z));
 
//  教科书方程会给出
//  cexp(∞+iNaN) ⇒ exp(∞)×(cis(NaN)) ⇒ NaN + I*NaN
//  但 C 给出 ±∞+i*nan
    double complex y = cexp(INFINITY + I*NAN);
    printf("%f%+f*i\n", creal(y), cimag(y));
}

可能的输出:

inf+inf*i 
inf+nan*i

C 也会处理多重无穷大,以在可能的地方保留方向信息,不管笛卡尔表示的固有限制:

实无穷大乘虚数单位,会给出对应符号的虚无穷大: i × ∞ = i∞ 。同理, i × (∞ – i∞) = ∞ + i∞ 指示合理的象限。

虚浮点数类型

虚浮点数类型模仿数学的虚数,即可以写成实数乘虚数单位的数:bi 三种虚数类型是

注意:同所有类型说明符,允许任意顺序:long double imaginary