C语言具有多种数据类型,用于存储不同类型的数据。大体可以分为基本数据类型和派生数据类型两大类。
一、基本数据类型
- 整型(Integer): 用于表示整数值,包括int、short、long和long long等类型,可以有不同的存储大小和范围。
- 浮点型(Floating-point): 用于表示实数值,包括float、double和long double等类型,可以有不同的精度和范围。
- 字符型(Character): 用于表示单个字符,通常使用char类型。
- 布尔型(Boolean): 用于表示真或假,C99标准引入了_Bool类型,通常用bool宏表示。
- 空类型(Void): 表示无类型,通常用于函数返回值或指针类型。
二、派生数据类型
- 指针(Pointer): 用于存储变量的地址,可以指向不同类型的数据。
- 数组(Array): 用于存储相同类型的多个数据元素。
- 结构体(Structure): 用于将不同类型的数据组合成一个自定义的数据类型。
- 联合体(Union): 与结构体类似,但所有成员共享同一块内存,用于节省空间。
- 枚举(Enumeration): 用于定义一组命名的整数常量。
三、题目
3.1 下面代码运行输出的结果是多少?
#include<stdio.h>
int main(void) {
unsigned char u8a = 256;
printf("u8a = %d",u8a);
return 0;
}
参考答案:在C语言中, unsigned 表示无符号,即该类型的值只能是正整数或零,而 char 表示字符,一个字节,即8位。所以取值范围为:[0, 2^8] = [0, 255]。因为它只有8位。当你将一个大于255的值(比如256)赋给 unsigned char 类型的变量时,会发生截断,只保留最低8位的值。
256的二进制:1 0000 0000
3.2 signed char 的数据范围是多少,为什么?
参考答案:signed char 表示有符号的8位字符,一个字节。值范围是 -128 到 127。
我们知道,signed 修饰的话,最高就是符号位:1代表负数,0代表整数。
正数的最大值就是:0111 1111 ,也即 64+32+16+8+4+2+1=127
我们还知道负数在计算机当中是以补码形式存在的。
为什么会引入补码呢?
因为计算机使用补码表示法来表示有符号整数,它有助于简化整数的加法和减法运算,并且不需要额外的操作来处理负数。
并规定正数三码合一:原码 = 反码 = 补码
负数最高位位符号位,原码 = 符号位 + 其正数的数值位
反码:符号位不变,数值位逐一取反。
补码:反码+1
对于有符号的8位二进制补码数,最高位是符号位,剩下的 7 位用于表示绝对值。因此,范围是 10000000(-128)到 01111111(127)
原码: 1000 0000
反码: 1111 1111
补码: 1000 0000
-128的原码是为什么会是1000 000 是有发生截断的。(个人理解)
3.3 0的原码、反码和补码
对于数字 0,它的原码、反码和补码都是相同的,因为在有符号的二进制表示中,0 是唯一一个没有正负号之分的数。以下是如何计算 0 的原码、反码和补码:
- 原码(Sign-Magnitude):
原码是直接使用二进制表示数的绝对值,并在最高位添加符号位(0 表示正数,1 表示负数)。
0 的原码是:00000000
- 反码(Ones’ Complement):
反码是将原码中除符号位外的每个位取反(0 变为 1,1 变为 0)。
0 的反码是:11111111
- 补码(Two’s Complement):
补码是在反码的基础上加 1。
0 的补码是:00000000
对于 0,原码、反码和补码都是相同的二进制表示,都是 00000000。在计算机中,0 表示为全 0 的二进制序列,无论是在原码、反码还是补码中,都没有正负号之分。
3.3 不同的系统上,类型所占据的字节长度是不同的
数据类型在不同编译器上占据的字节长度可能会有所不同,主要是由于编译器和计算机体系结构的差异导致的。以下是一些原因:
计算机体系结构: 不同的计算机体系结构(如 32 位、64 位等)对数据的处理方式不同。例如,64 位系统的处理器通常支持更大的数据寻址和处理能力,因此可以容纳更大的数据类型。而 32 位系统可能会限制数据类型的大小。
编译器实现: 不同的编译器可能使用不同的优化策略、数据对齐方式等来处理数据类型。这可能导致不同的编译器在内存布局上有所不同,进而影响数据类型的字节长度。
操作系统: 操作系统也可能影响数据类型的字节长度。例如,某些操作系统可能在不同数据类型之间保持特定的对齐方式,以提高访问速度。这可能会影响数据类型的大小。
标准规范: C 语言标准规范并没有明确规定数据类型在不同编译器上的精确大小,只是给出了最小的要求。因此,编译器实现者可以在符合标准的前提下进行适当的调整。
历史和遗留问题: 一些历史因素和遗留代码可能会影响数据类型在不同编译器上的大小。一些编译器可能会保持对旧代码的兼容性,因此可能会在数据类型大小方面存在差异。
综上所述,数据类型在不同编译器上占据的字节长度差异主要源自计算机体系结构、编译器实现、操作系统和历史因素等多个因素的综合影响。在编写跨平台代码时,需要格外注意数据类型的大小和兼容性。