4. C语言的数据类型

C语言中,数据类型指的是用于声明不同类型的变量或函数的一个广泛的系统。变量的类型决定了变量存储占用的空间,以及如何解释存储的位模式。

这里强调:

C 是一种静态类型语言。在实际使用变量之前,必须明确声明变量的名称以及要存储的数据类型。

C 也是一种强类型语言,这意味着不允许将一种数据类型自动或隐式地转换为另一种数据类型。

C 中的类型可分为以下几种:

序号类型与描述
1基本数据类型
它们是算术类型,包括整型(int)、字符型(char)、浮点型(float)和双精度浮点型(double)。
2枚举类型:
它们也是算术类型,被用来定义在程序中只能赋予其一定的离散整数值的变量。
3void 类型:
类型说明符 void 表示没有值的数据类型,通常用于函数返回值。
4派生类型:
包括数组类型、指针类型和结构体类型。

基础数据类型

注意:以下是典型的数据位长和范围。编译器可能使用不同的数据位长和范围。请参考具体的参考。

在标准头文件limits.h 和 float.h中说明了基础数据的长度。float,double和long double的范围就是在IEEE 754标准中提及的典型数据。另外,C99添加了新的复数类型,C11添加了原子类型,它们不在本条目讨论范围内。关于这些类型的具体含义和部分细节,参见资料类型,最后一列写出了这些类型在硬件层面的类型(x86&x86_64实现)

关键字字节(字节)范围格式化字符串硬件层面的类型备注
char1bytes通常为-128至127或0至255,与体系结构相关%c字节(Byte)大多数情况下即signed char;

在极少数1byte != 8bit或不使用ASCII字符集的机器类型上范围可能会更大或更小。其它类型同理。

unsigned char1bytes通常为0至255%c、%hhu字节
signed char1bytes通常为-128至127%c、%hhd、%hhi字节
int2bytes(16位系统) 或
4bytes
-32768至32767或
-2147483648至2147483647
%i、%d字(Word)或双字(Double Word)signed int(但用于bit-field时,int可能被视为signed int,也可能被视为unsigned int)
unsigned int2bytes 或
4bytes
0至65535 或
0至4294967295
%u字或双字
signed int2bytes 或
4bytes
-32768至32767 或
-2147483648至2147483647
%i、%d字或双字
short int2bytes-32768至32767%hi、%hdsigned short
unsigned short2bytes0至65535%hu
signed short2bytes-32768至32767%hi、%hd
long int4bytes 或
8bytes[1]
-2147483648至2147483647 或
-9223372036854775808至9223372036854775807
%li、%ld长整数(Long Integer)signed long
unsigned long4bytes 或
8bytes
0至4294967295 或
0至18446744073709551615
%lu整数(Unsigned Integer)或

长整数(Unsigned Long Integer)

依赖于实现
signed long4bytes或
8bytes
-2147483648至2147483647 或
-9223372036854775808至9223372036854775807
%li、%ld整数(Signed Integer)或

长整数(Signed Long Integer)

依赖于实现
long long8bytes-9223372036854775808至9223372036854775807%lli、%lld长整数(Long Integer)
unsigned long long8bytes0至18446744073709551615%llu长整数(Unsigned Long Integer)
float4bytes2.939x10−38至3.403x10+38 (7 sf)%f、%e、%g浮点数(Float)
double8bytes5.563x10−309至1.798x10+308 (15 sf)%lf、%e、%g双精度浮点型(Double Float)
long double10bytes或
16bytes
7.065x10-9865至1.415x109864 (18 sf或33 sf)%lf、%le、%lg双精度浮点型(Double Float)在大多数平台上的实现与double相同,实现由编译器定义。
_Bool1byte0或1%i、%d布尔型(Boolean)

#include <stdio.h>

#include <stdlib.h>

#include <limits.h>

#include <float.h>

int main(int argc, char** argv) {

printf("CHAR_BIT : %d\n", CHAR_BIT);

printf("CHAR_MAX : %d\n", CHAR_MAX);

printf("CHAR_MIN : %d\n", CHAR_MIN);

printf("INT_MAX : %d\n", INT_MAX);

printf("INT_MIN : %d\n", INT_MIN);

printf("LONG_MAX : %ld\n", (long) LONG_MAX);

printf("LONG_MIN : %ld\n", (long) LONG_MIN);

printf("SCHAR_MAX : %d\n", SCHAR_MAX);

printf("SCHAR_MIN : %d\n", SCHAR_MIN);

printf("SHRT_MAX : %d\n", SHRT_MAX);

printf("SHRT_MIN : %d\n", SHRT_MIN);

printf("UCHAR_MAX : %d\n", UCHAR_MAX);

printf("UINT_MAX : %u\n", (unsigned int) UINT_MAX);

printf("ULONG_MAX : %lu\n", (unsigned long) ULONG_MAX);

printf("USHRT_MAX : %d\n", (unsigned short) USHRT_MAX);

return 0;

当你编译并执行上述程序时,它会产生以下结果

CHAR_BIT    :   8
CHAR_MAX    :   127
CHAR_MIN    :   -128
INT_MAX     :   2147483647
INT_MIN     :   -2147483648
LONG_MAX    :   9223372036854775807
LONG_MIN    :   -9223372036854775808
SCHAR_MAX   :   127
SCHAR_MIN   :   -128
SHRT_MAX    :   32767
SHRT_MIN    :   -32768
UCHAR_MAX   :   255
UINT_MAX    :   4294967295
ULONG_MAX   :   18446744073709551615
USHRT_MAX   :   65535

结构

结构(structure variable)允许构造由多个基础数据类型组合而成的复杂结构[2]。结构为面向对象编程的蓝本。以下示例通过结构和结构体里的指针实现了二叉树结构:

typedef struct Bintree {
    int data;
    struct bintree *lchild; // left child of the node
    struct bintree *rchild; // right child of the node
} bintree; // 自定义 bintree 类型

为结构定义变量时通常会用到动态内存分配

#define mktree() (bintree *)malloc(sizeof(bintree)) // 分配该结构所需的内存单元数量
bintree *tree;
tree = mktree(); // 分配到 tree 指针
tree->data = 1;
tree->lchild = mktree();
...

由于C语言不具备自动垃圾收集(Garbage Collection)功能,使用完毕后调用free(treePtr)来释放之前通过malloc(size)分配的内存。详见这里。 在C99标准中,还添加了名为伸缩型数组成员的特性[3],若需了解更多信息可参见文档或其它材料。

联合

联合(union)与结构相类似,但不同的是,联合在某一特定时刻只有最后被使用的成员的值是确定的,因此一个联合只使用所有成员中所占空间最大的成员所使用的内存。因此,一次只能使用一个元素。

然而,一些编译器可以通过编译参数或#pragma的方式强制联合使用与所有成员所占储存空间的和相等的储存空间,在这种情况下,除最后被使用的成员外,其余成员的值是未定义的[2]。以下给出了联合的一个声明:

union foo{
    int bar;
    double foobar;
};

foo.bar = 8;
foo.foobar = 3.14;

在这个例子中,假设使用32位平台编译,一个double变量占8字节,一个int变量占2字节(由上表得),则该联合所占大小即为double类型的大小——8字节。在这段程序执行完毕后,foo.bar的值是未定义的,而foo.foobar的值为3.14。

枚举

枚举(enumerated type)用来声明一组整数常量。默认情况下,枚举声明格式为enum type {value1,value2,...,valuen};此时value1,value2分别为0,1,直到n-1。事实上,枚举类型在C语言实现中是以int类型储存的[2]。以下是枚举的一个声明:

enum a { b , c , d };

在此之后,便可以以如下方式使用:

enum a foo;
foo = b;
if(foo != c) //等同于if(foo != 1)
{
    do_something();
}

而此时的b,c,d分别为0,1,2。 另外,也可以手动为枚举列表中的常量赋值。下面是一个例子:

enum colour {red = 100,blue = 700,yellow = 200};

则此时red,blue,yellow的值分别为100,700,200.

需要注意的是,枚举在C和C++中所表现的行为有一些细微的差异。参见C与C++的兼容性

C 语言中的数组数据类型

数组是存储在连续内存位置的多个相同数据类型的值的集合。数组的大小在方括号 [] 中提及。例如,

int marks [ 5 ] ;

数组可以在声明时初始化。要分配的值放在括号中。

int marks [ ] = { 50 , 56 , 76 , 67 , 43 } ;

C 还支持多维数组。要了解有关数组的更多信息,后面会介绍。

C 语言中的指针数据类型

指针是一种特殊的变量,用于在内存中存储另一个变量/对象的地址或引用。指针变量的名称以星号 (*) 为前缀。指针变量的类型和要指向的变量/对象必须相同。

int x ; int *y ; y = &x ;

这里,“y”是一个指针变量,它存储了“int”类型变量“x”的地址。

类型转换

类型转换是将一个数据类型的值转换为另一种数据类型的值。

C 语言中有两种类型转换:

  • 隐式类型转换:隐式类型转换是在表达式中自动发生的,无需进行任何明确的指令或函数调用。它通常是将一种较小的类型自动转换为较大的类型,例如,将int类型转换为long类型或float类型转换为double类型。隐式类型转换也可能会导致数据精度丢失或数据截断。

  • 显式类型转换:显式类型转换需要使用强制类型转换运算符(type casting operator),它可以将一个数据类型的值强制转换为另一种数据类型的值。强制类型转换可以使程序员在必要时对数据类型进行更精确的控制,但也可能会导致数据丢失或截断。

隐式类型转换实例:

实例

int i = 10;
float f = 3.14;
double d = i + f; // 隐式将int类型转换为double类型

显式类型转换实例:

实例

double d = 3.14159;
int i = (int)d; // 显式将double类型转换为int类型,此时i = 3.

布尔类型

C99之前,C语言的标准没有提供布尔类型,但是这不意味着C90不能表示布尔值的概念。C中的所有布尔运算(&&, ||)以及条件声明(if, while)都以非零值代表,零值代表。这样,在其他类型如一个整数或一个枚举中保存布尔值就变得很平常。为了方便,常常为布尔类型创建一个typedef来和一些已存在的数据类型相关联。C99标准也提供了一个内置的布尔类型。

为了说明C中的布尔型,注意以下C代码:

if (my_variable) {
  printf("True!\n");
} else {
  printf("False!\n");
}

等价于:

if (my_variable != 0) {
  printf("True!\n");
} else {
  printf("False!\n");
}

简单来说这就是一个整数类型。由于C标准要求0用在指针上下文中时要代表空指针,上面的概念也可以用来检查一个指针是否为空,虽然一些程序风格不建议这样用。这种情况同样适用于浮点值,当比较它们的时候要特别小心,因为它们通常包含四舍五入的结果。通常,整型用来包含布尔变量。

虽然为了测试一个变量的真假值时没必要来命名真或假,但是在给它们分配值的时候却是需要的。(一种方法是使用零值和一,这样做的好处是语言独立。)其他方法,enum关键字允许在语言中根据你的选择来命名元素,例如:

typedef enum { FALSE, TRUE } boolean;
...
boolean b;

如下典型的预处理宏经常被使用。

#define FALSE 0
#define TRUE 1
...
int f = FALSE;

有时TRUE可能被定义为-1或~0(位运算0的补)。这意味着在现在常见的二补数计算机架构的整型中所有的位都被设置为1。

但是,在C中任意非零值都代表真就带来了问题,因为TRUE由一个特定的值来表示,因此在其他语言中if (foo == TRUE) ...只不过是多余的,而在C中,就是错误的代码。

C99中有bool类型,取值为truefalse,定义在<stdbool.h>头文件中:

#include <stdbool.h>
bool b = false;
...
b = true;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值