在C/C++语言中,有很多种类型,而整型是用的最多的
声明一个变量:
int num; // 声明一个整型变量声明并初始化一个变量:
int cnt = 0; // 声明并初始化一个变量先声明一个变量,再赋值:
// 先声明一个变量 再赋值
int exm; // 声明一个变量,它的值是随机的
exm = 10;// 给这个变量赋值上面这两行代码和int exm = 10;的作用是一样的,但是赋值和初始化是两个不同的操作,
赋值是给已经存在的变量进行操作,初始化是在变量定义时进行操作
必须强调这里未初始化的危险。如果一个变量没有初始化,C/C++ 编译器不会报告错误,甚至不会发出警告。C/C++标准中未初始化变量的值也没有明确定义。你可能会从一个未初始化的变量中得到一个随机值。为了程序的健壮性,强烈建议初始化变量,哪怕不知道这个变量到底值为多少,初始化成0也是很好的
int main() {
int num1;
int num2 = 10;
cout << num1 << endl << num2 << endl;
}VS2022强制检查,报错了

使用C语法也一样报错

int 的宽度(以位为单位)在 C 和 C++ 标准中并不是固定的。标准 int 应具有 32 位。除了 int,还有 short int、long int 和 long long int``short int 是 16 位。int 是 16 位或 32 位。long int 是 32 位或 64 位(取决于编译器)。long long int 是 64 位。char 也是一种常用的整数类型。有人可能会感到困惑,认为 char 仅用于字符。由于字符被编码为整数值,char 确实是一种整数类型,并且具有 8 位。char 对英语字符来说足够宽,但对中文和其他一些字符则不够。char16_t 和 char32_t 已在 C++11 中引入,表示 16 位和 32 位的范围。
char c = 'C'; // ASCII码为80char c = 80;// 十进制80char c = 0x50;// 十六进制50 转为十进制80上面这三行代码是等效的,在我们编码时,看着每个变量的类型不同,其实到计算机底层,所有数据都被表示成01串了,机器只能识别01两个指令
以下是各个整型类型所占空间大小
类型 | 所占比特位大小 |
|---|---|
char | 8 |
short (short int) | 16 |
int | 16 or 32 |
long (long int) | 32 or 64 |
long long (long long int) | 64 |
我们可以用sizeof操作符来获取类型大小
int main() {
cout << sizeof(char) << endl;
cout << sizeof(short) << endl;
cout << sizeof(int) << endl;
cout << sizeof(long) << endl;
cout << sizeof(long long) << endl;
return 0;
}
在我的机器上long是四字节
signed 或 unsigned 可以在整数类型名称之前使用,以指示整数是有符号的还是无符号的。当整数是有符号时,关键字 signed 可以省略。这意味着 int 是用于 signed int,而 short 是用于 signed short。如果整数是有符号的,最高位(int 的第 32 位)将是其符号位。如果符号位为 1,则为负数;如果为 0,则为正数。
有符号整数和无符号整数如下面的图所示:

数据在底层用0和1这两个数存储,一个字节(8bit)可以表达多少个数?————>每个位置两种选择,共八个位置:
个

对于无符号数来说,最大的数就是
那怎么表示负数呢?牺牲最高位作为符号位,符号位为 1,则为负数;如果为 0,则为正数。,这便是原码
这样就能得到以下分类:

符号位后两个极端,全0或者全1,正数可以表达
个,负数也可以表达
个,但是出现一个问题:0被重复表达了两次!+0和-0,所以,原码表示法出现了缺陷:
所以,引入补码
对于一个钟表,假定指针指向了10点的位置,我现在要将其拨到6点位置,有两种方式:
,转完了一圈,18 % 12 = 6

钟表是一个模十二的系统:那么就可以理解为
这里的-4和8是相等的关系,那么就可以说8的补码是-4,同样的,9的补码是-3
在模十二的系统中,都遵循着一个原则:互为补码的两个数,不管符号,相加和为12,8+4,9+3,10+2的结果都是12
那么,在一个模
的运算系统中,有两个数
和
,一定满足
那么就引出了补码的运算:加法和减法的运算逻辑相同
如果做减法,我们只需要加上这个数的补码即可,将减法转换成了加法,这样加减法共用一套逻辑
**”8位2进制数“模运算系统(mod
)**中,有两个数
和
,一定满足
现在用
减去一个1,即是
1 0000 0000 - 0000 0001————> 得到1111 1111,这个数,是-1的表达,所以-1的表达,就是
减去1,相当于把原来的0000 0001各位取反再加1————>1111 1111,现在使得1111 1111 + 0000 0001————>1 0000 0000即是
,这便是负数的补码
正数的补码是正数本身,负数的补码是符号位不变,其他位取反,末位加一
例如:-1:原码1000 0001 补码:1111 1111
现在回到之前的分类:

这样原来的-0:1000 0000就可以表示一个更小的数了
我们再将1000 0000转换成原码检查一下:
除了符号位全部取反->1111 1111,末尾+1->1 0000 0000,
八位存不下,最高位截断:0000 0000 ->0
,满足“8位2进制数“模运算系统(mod
)的规则
以下是常见整型的取值范围:

我们可以继续用一个圆来理解:

short int等其他类型同理
关系运算符 | 类型 | 结果 | 说明 |
|---|---|---|---|
0 == 0U | 无符号 | 1 | 同为零 |
-1 < 0 | 有符号 | 1 | 有符号类型-1<0 |
-1 < 0U | 无符号 | 0 | 11…11( 2 32 − 1 2^{32}-1 232−1) > 0 |
2147483647 > -2147483647 -1 | 有符号 | 1 | 正数 >负数 |
2147483647U > -2147483647 - 1 | 无符号 | 0 | 01…1( 2 31 − 1 2^{31}-1 231−1)<10…0( 2 31 2^{31} 231) |
2147483647 >(int)2147483647U | 有符号 | 1 | 01…1( 2 31 − 1 2^{31}-1 231−1)>10…0( − 2 31 -2^{31} −231) |
-1 >-2 | 有符号 | 1 | 有符号类型-1>-2 |
(unsigned)-1 > -2 | 无符号 | 1 | 11…11( 2 32 − 1 2^{32}-1 232−1) > 11…10( 2 32 − 2 2^{32}-2 232−2) |
) > 02147483647 > -2147483647 -1有符号1正数 >负数2147483647U > -2147483647 - 1无符号001…1(
)<10…0(
)2147483647 >(int)2147483647U有符号101…1(
)>10…0(
)-1 >-2有符号1有符号类型-1>-2(unsigned)-1 > -2无符号111…11(
) > 11…10(
)
对于int和unsigned int:

int main() {
int x = -1;
unsigned u = 2147483648;
printf("x = %u = %d\n", x, x);
printf("u = %u = %d\n", u, u);
return 0;
}x = -1: -1 作为 32 位有符号整数(补码)存储为全 1:11111111 11111111 11111111 11111111%u(无符号整数格式)输出时,这个二进制被解读为无符号数,值为 4294967295(2³²-1)%d(有符号整数格式)输出时,正确解读为 -1u = 2147483648: 10000000 00000000 00000000 00000000%u 输出时,正确显示为 2147483648%d 输出时,这个二进制被解读为有符号整数(补码),由于最高位是 1(符号位),表示这是一个负数。在 32 位有符号整数中,这个值恰好是最小的负数 -2147483648
这个例子展示了C/C++整数的二进制存储本质:相同的二进制序列,根据解释方式(有符号 / 无符号)的不同,会呈现出完全不同的数值。格式化字符 %d 和 %u 决定了如何解读内存中的二进制数据,而不是改变数据本身。
int main() {
int b = -1;
char c = -1;
printf("%u,%u\n",b, c);
return 0;
}int b = -1:作为 32 位有符号整数,-1的补码表示为全 1(11111111 11111111 11111111 11111111)char c = -1:在大多数系统中char是 8 位,-1的补码表示为11111111printf输出规则: %u(无符号整数格式)输出时,所有整数类型都会被提升为unsigned intb作为 int 直接转换为 unsigned int,全 1 的 32 位二进制对应4294967295c作为 char 首先进行符号扩展(因为是有符号 char),8 位的11111111扩展为 32 位的11111111 11111111 11111111 11111111,再转换为 unsigned int 也得到4294967295
这个例子展示了C/C++整数提升和符号扩展的规则:当小整数类型参与表达式运算或格式化输出时,会先提升为 int (有符号扩展),再根据格式控制符进行相应转换。