类型

来自cppreference.com
< c‎ | language

(参阅算术类型及C库提供的类型关联的工具列表,查看更多内建类型的细节)

对象函数表达式拥有叫做类型的属性,它决定存储于对象或表达式求得的二进制值的转译方式。

目录

[编辑] 类型分类

C类型系统包含下列类型:

  • void类型
  • 基本类型
  • char类型
  • 有符号整数类型
  • 标准:signed charshortintlonglong long (C99起)
  • 扩展:实现定义,例如__int128
  • 无符号整数类型
  • 标准:_Bool (C99起)unsigned charunsigned short, unsigned intunsigned longunsigned long long (C99起)
  • 扩展:实现定义,例如__uint128
  • 浮点类型
  • 实浮点类型:floatdoublelong double
  • 复数类型:float _Complexdouble _Complexlong double _Complex
  • 虚数类型:float _Imaginarydouble _Imaginarylong double _Imaginary
  • 导出类型

每一个列于上方的类型可以存在数种资格版本,对应资格符constvolatilerestrict中的一个、二个或全部三个(在允许资格符语义的场合)。

[编辑] 类型组别

  • 对象类型:函数类型以外的所有类型
  • 字符类型charsigned charunsigned char
  • 整数类型char、有符号整数类型、无符号整数类型、枚举类型
  • 实数类型:整数类型和实浮点类型
  • 算术类型:整数类型和浮点类型
  • 标量类型:算术类型和指针类型
  • 聚合类型:数组类型和结构体类型
  • 导出声明符类型:数组类型、函数类型和指针类型

[编辑] 兼容类型

C程序中,在不同翻译单元引用同一对象和函数的声明不必拥有相同类型。它们只需要用足够相近的类型,正式称呼是兼容类型。对函数调用和左值访问的应用相同;使用参数类型必须与声明参数类型兼容,且左值表达式类型必须与被访问的对象类型兼容

类型TU兼容,当

  • 它们是同一类型(同名或是由typedef引入的别名)
  • 它们是兼容的非资格类型的同一cvr资格版本
  • 它们是指针类型且指向兼容类型
  • 它们是数组类型,且
  • 它们的元素类型兼容,且
  • 若它们均有常量大小而大小相同。注意:边界未知的数组可于任何元素类型兼容的数组兼容。VLA与任何元素类型兼容的数组兼容。 (C99起)
  • 他们均为结构体/联合体/枚举类型,且
  • (C99)若一个声明带标签,则另一个也必须声明带同样的标签。
  • 若皆为完整类型,他们的成员必须数目准确对应,都要以兼容的类型声明,且拥有匹配的名称。
  • 另外,若它们是枚举类型,则对应成员必须有相同的值。
  • 另外,若它们是结构体或联合体,
  • 对应元素必须以同一顺序声明(仅限结构体)
  • 对应位域必须有相同宽度。
  • 一个是枚举类型且另一个是枚举的基础类型
  • 它们是函数类型,且
  • 它们的返回值兼容
  • 它们使用参数列表,参数的数量(包含省略号的使用)相同,对应参数拥有兼容类型
  • 一个是旧式(无参数)定义,另一个拥有参数列表,参数列表不使用省略号,且(在函数参数类型调整后)每个参数兼容对应的默认参数提升后的旧式参数
  • 一个是旧式(无参数)定义,另一个拥有参数列表,参数列表不使用省略号,且(在函数参数类型调整后)所有参数不受默认参数提升影响

类型charsigned charunsigned char皆不兼容。

若两个声明引用同一变量或函数,却使用了不兼容的类型,则程序行为是未定义的。

// 翻译单元1
struct S {int a;};
extern struct S *x;  // 兼容TU2的x,但不兼容TU3的x
// 翻译单元2
struct S;
extern struct S *x; // 兼容两个x
// 翻译单元3
struct S {float a;};
extern struct S *x; // 兼容TU2的x,但不兼容TU1的x
 
// 行为未定义
// 翻译单元1
#include <stdio.h>
struct s {int i;}; // 兼容TU3的s,但不兼容TU2的s
extern struct s x = {0}; // 兼容TU3的x
extern void f(void); // 兼容TU2的f
int main(void)
{
   f();
   return x.i;
}
// 翻译单元2
struct s {float f;}; // 兼容TU4的s,但不兼容TU1的s
extern struct s y = {3.14}; // 兼容TU4的y
void f() // 兼容TU1的f
{
   return;
}
// 翻译单元3
struct s {int i;}; // 兼容TU1的s,但不兼容TU2的s
extern struct s x; // 兼容TU1的x
// 翻译单元4
struct s {float f;}; // 兼容TU2的s,但不兼容TU1的s
extern struct s y; // 兼容TU2的y
 
// 行为良好定义:对象和函数的多重声明只是必须拥有兼容类型,而非类型自身

注意:C++没有兼容类型的概念。在不同翻译单元声明两个兼容但不相同类型的C程序是非法的C++程序。

[编辑] 合成类型

合成类型是从两个兼容类型构建的,它与两个类型兼容,并满足下列条件:

  • 若两类型均为数组,则应用下列规则:
  • 若一个类型是已知大小的数组,则合成类型是该大小的数组。
  • 否则,若一个类型是长度指定于未求值表达式的变量长度数组,则行为未定义。 (C99起)
  • 否则,若一个类型是长度已指定的VLA,则合成类型是该长度的VLA。 (C99起)
  • 否则,若一个类型是长度未指定的VLA,则合成类型是长度未指定的VLA。 (C99起)
  • 否则,两个类型均为长度未指定的数组,则合成类型是长度未指定的数组。

合成类型的元素类型是两种元素类型的合成类型。

  • 若只有一个类型是带参数列表的函数类型(函数原型),则合成类型是带参数类表的函数原型。
  • 若两个类型都是带参数列表的函数类型,则合成类型的参数类型列表的每个参数类型是对应参数的合成类型。

此规则可递归地用于类型导出源的类型。

对于拥有内部或外部链接,声明于标识符前置声明可见的作用域的标识符,若前置声明指定了内部或外部链接,则在后部声明的标识符类型会作为合成类型。

/* 两个文件作用域中的定义 */
int f(int (*)(), double (*)[3]);
int f(int (*)(char *), double (*)[]);
/* 合成类型 */
int f(int (*)(char *), double (*)[3]);

[编辑] 未完成类型

未完成类型是缺失了确定该类型对象大小的充分信息的类型。一个未完成类型可以在翻译单元中的某些点被完成。

下列类型是未完成的:

  • 类型void。此类型不能被完成。
  • 大小未知的数组类型。它可以为后面的限定大小的声明所完成。
  • 内容未知的结构体或联合体。它可以为同一作用域中,定义其内容的相同结构体或联合体的声明所完成。

[编辑] 类型名

一个类型可能在要在拥有异于声明的语境中指出名称。在这些情况下,使用类型名。它们是用于声明此类型对象或函数的,跟随声明符(见声明)的类型限定符类型资格符列表在文法上准确相同,除了标识符被忽略:

int n; // 声明int
sizeof(int); // 使用类型名
 
int *a[3]; // 声明3个指向int指针构成的数组
sizeof(int *[3]); // 使用类型名
 
int (*p)[3]; // 声明指针,指向3个int的数组
sizeof(int (*)[3]); // 使用类型名
 
int (*a)[*] // 声明指向VLA的指针(于函数参数)
sizeof(int (*)[*]) // 使用类型名(于函数参数)
 
int *f(void); // 声明函数
sizeof(int *(void)); // 使用类型名
 
int (*p)(void); // 声明指向函数的指针
sizeof(int (*)(void)); // 使用类型名
 
int (*const a[])(unsigned int, ...) = {0}; // 指向函数的指针构成的数组
sizeof(int (*const [])(unsigned int, ...)); // 使用类型名

除去环绕标识符的冗余括号外,括号在类型名中是有意义的,并表示“无参数限定的函数”:

int (n); // 声明类型int的n
sizeof(int ()); // 使用类型“返回int的函数”

类型名可用于下列场合:

(C99起)
(C11起)


一个类型名可引入新类型:

void* p = (void*)(struct X {int i;} *)0;
// 类型名 "struct X {int i;}*" 用于转换类型表达式
// 引入了新类型 "struct X"
struct X x = {1}; // struct X现在于作用域中

[编辑] 参考

  • C11 standard (ISO/IEC 9899:2011):
  • 6.2.5 Types (p: 39-43)
  • 6.2.6 Representations of types (p: 44-46)
  • 6.2.7 Compatible type and composite type (p: 47-48)
  • C99 standard (ISO/IEC 9899:1999):
  • 6.2.5 Types (p: 33-37)
  • 6.2.6 Representations of types (p: 37-40)
  • 6.2.7 Compatible type and composite type (p: 40-41)
  • C89/C90 standard (ISO/IEC 9899:1990):
  • 3.1.2.5 Types
  • 3.1.2.6 Compatible type and composite type

[编辑] 参阅

类型C++文档