算术类型

< c‎ | language

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

布尔类型

  • _Bool (亦可作为宏 bool 使用) - 类型,足以保有二个值之一: 1 与 0 (亦可作为宏 truefalse 使用)。

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

(C99 起)

字符类型

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

注意:标准亦定义了 typedefwchar_tchar16_tchar32_t (C11 起) 以表示宽字符。

整数类型

  • 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 起)

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

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

类型指定符 等价类型 数据模型中的位宽
C 标准 LP32 ILP32 LLP64 LP64
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/4 ( int 为 16 位, long 与指针为 32 位)
  • Win16 API
  • ILP324/4/4 ( int 、 long 及指针为 32 位);
  • Win32 API
  • Unix 及类 Unix 系统( Linux 、 Mac OS X )

64 位系统:

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

其他数据模型非常稀有。例如, ILP648/8/8 : int 、 long 及指针均为 64 位)仅出现于某些早期 64 位 Unix 系统(例如 Unicos on Cray )。

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

实浮点类型

C 拥有三种表示实浮点值的类型:

  • float - 单精度浮点类型。若支持则匹配 IEEE-754 32 位浮点类型。
  • double - 双精度浮点类型。若支持则匹配 IEEE-754 64 位浮点类型。
  • long double - 扩展精度浮点类型。若支持则匹配 IEEE-754 扩展浮点类型,否则匹配某些非标准扩展浮点类型,只要其精度高于 double 且范围至少与 double 相同,否则再匹配 double 类型。某些 x86 与 x86-64 实现使用 80 位x 87 浮点类型。

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

  • 无穷大(正与负),见 INFINITY
  • 负零-0.0。它与正零比较相等,但对于某些算术运算有意义(例如 1.0/0.0 == INFINITY ,但 1.0/-0.0 == -INFINITY )。
  • 非数( NaN ),它与任何值比较不相等(包括其自身)。有多种位模式表示 NaN ,见 nanNAN 。注意 C 对 NaN ( IEEE-754 所指定的)信号不作任何注意,并安静处理所有 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__(C11),则不提供复数类型(还有库头文件 <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 <stdio.h>
#include <complex.h>
#include <math.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 + i*%f\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 + i*%f\n", creal(y), cimag(y));
 
}

可能的输出:

inf + i*inf 
inf + i*nan

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

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

虚浮点类型

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

注意:同所有类型指定符,允许任意顺序: long double imaginaryimaginary long double ,甚至 double imaginary long 都指名同一类型。

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

输出:

1/(3.0i) = -0.3i

推荐编译器定义 __STDC_IEC_559_COMPLEX__ ,但不要求支持虚数。 POSIX 推荐检查是否定义宏 _Imaginary_I 以鉴别是否支持虚数。

(C99 起)
(C11 前)

若定义 __STDC_IEC_559_COMPLEX__ ,则支持虚数。

(C11 起)

三种虚数类型各拥有与其对应实数类型float 之于 float imaginarydouble 之于 double imaginarylong double 之于 long double imaginary )相同的对象表示对齐要求

注意:尽管如此,虚数类型是独立的,且与其对应实数类型不兼容,这禁止别名使用。

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

自增和自减不定义于虚数类型。

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

虚数类型零通过自然记号 x + I*y (其中 I 定义为 _Imaginary_I )表示所有复数成为可能。若无虚数类型,则无法自然地创建一些特殊复数值。例如,若 I 被定义为 _Complex_I ,则书写 0.0 + I*INFINITY 会给出有 NaN 实部的结果,而必须用 CMPLX(0.0, INFINITY) 替代之。拥有负零虚部的数亦然,这对于使用存在分支的库函数有意义,例如 csqrt :若 I 定义为 _Complex_I,则 1.0 - 0.0*I 结果有正零的虚部,并要求用 CMPLXconj 获得负零虚部。

虚数类型亦会简化实现:复数乘虚数可以直接实现为二次乘法,若支持虚数,而非四次乘法和二次加法。

(C99 起)

关键词

char, int, short, long, signed, unsigned, float, double. _Bool, _Complex, _Imaginary

值域

下表提供常用数值表示极限的参考。因为 C 标准允许任何有符号整数表示,该表给出两种最小保证要求(对应反码原码)和最常用实现补码的极限。尽管所有通行数据模型(含 ILP32 、 LP32 、 LP64 、 LLP64 全体)都采用补码表示。

类型 位大小 格式 值域
粗略 准确
字符 8 有符号(反码) -127127
有符号(补码) -128127
无符号 0255
整数 16 有符号(反码) ± 3.27 · 104 -3276732767
有符号(补码) -3276832767
无符号 06.55 · 104 065535
32 有符号(反码) ± 2.14 · 109 -2,147,483,6472,147,483,647
有符号(补码) -2,147,483,6482,147,483,647
无符号 04.29 · 109 04,294,967,295
64 有符号(反码) ± 9.22 · 1018 -9,223,372,036,854,775,8079,223,372,036,854,775,807
有符号(补码) -9,223,372,036,854,775,8089,223,372,036,854,775,807
无符号 01.84 · 1019 018,446,744,073,709,551,615
浮点数 32 IEEE-754
  • 最小非正规:
    ± 1.401,298,4 · 10-45
  • 最小正规:
    ± 1.175,494,3 · 10-38
  • 最大:
    ± 3.402,823,4 · 1038
  • 最小非正规:
    ±0x1p-149
  • 最小正规:
    ±0x1p-126
  • 最大:
    ±0x1.fffffep+127
64 IEEE-754
  • 最小非正规:
    ± 4.940,656,458,412 · 10-324
  • 最小正规:
    ± 2.225,073,858,507,201,4 · 10-308
  • 最大:
    ± 1.797,693,134,862,315,7 · 10308
  • 最小非正规:
    ±0x1p-1074
  • 最小正规:
    ±0x1p-1022
  • 最大:
    ±0x1.fffffffffffffp+1023

注意:实际(与保证最小值相对)的范围可在库头文件 <limits.h> 和 <float.h> 中获得

参阅