(1)将i定义为无符号的整形:
①当i=0时,打印出来是0;
②再次执行i--,此时i=-1,在内存中存储为补码形式:0xFFFFFFFF
③i是无符号类型,所以最高位不是符号位,满足循环条件,所以将继续循环执行代码
④最终循环将一直执行,永远不会出来
1 unsigned i ; 2 for (i=9;i>=0;i--) 3 { 4 printf("%u ",i); 5 }
代码运行结果:处于死循环之中
指针
(1)
int main(void) { int a[4] = {1, 2, 3, 4}; int *ptr1=(int *)(&a+1); int *ptr2=(int *)((int)a+1); printf(“%x, %x/n”, ptr1[-1], *ptr2); return 0; } 问,在x86平台下输出啥?
1、&a+1
首先明确,a是一个具有4个整型变量的数组的名字,具体地说是这种数组的首元素的首地址,而&a是数组的首地址,请注意措辞。而关于指针加1,则需要指针运算的知识。没学过指针运算或者已经忘记了这个知识点的朋友们,下面就是关于指针运算你需要知道的事实:
就像上面的例子那样,式子&a+1表示的是指针加法运算,而不是普通的数值加法运算,之所以会这样是因为&a是一个指针而非普通数值(虽然它本质上也是一个整数)。那么你会问:假如此时&a=0xFFFF5700,那么&a+1是多少呢?答案是:取决于&a的类型 。
a) 如果&a是一个指向char型的指针,那么&a+1 = 0xFFFF5701 b) 如果&a是一个指向short型的指针,那么&a+1 = 0xFFFF5702 c) 如果&a是一个指向int型的指针,那么&a+1 = 0xFFFF5704 (32位机器) d) 如果&a是一个指向某种结构体struct foo的指针,那么&a+1 = 0xFFFF5700+sizeof(struct foo) ……
指针加1不是指针内容简单地加1,而是让指针指向下一个数据 ,加2就是让指针指向下两个数据,这个数据的类型就是指针指向的类型,所以指针的加法究竟会让这个指针指向哪里,取决于这个指针指向的数据类型。
因此,综上所述,当&a与整数1做加法时,实际上是指针的加法,加1的含义是:令指针a指向下一个数据 ,下一个数据是啥?当然是紧挨着的下一个具有4个整型变量的数组了(因为&a的类型是指向具有4个整型变量的数组的指针嘛),于是a的指向了4的下一个地址,在用此值初始化ptr1,因此ptr1的指向如图所示:
![](https://ask.qcloudimg.com/http-save/yehe-5426759/b2yz60ebl7.jpeg?imageView2/2/w/1620)
由于在ptr1初始化的时候,令&a+1强制转换成整型指针,因此ptr1[-1]相当于把ptr1往前挪一个整型大小,即4个字节。 如下图:
![](https://ask.qcloudimg.com/http-save/yehe-5426759/h4euf5zucv.jpeg?imageView2/2/w/1620)
显然,打印出的第一个数字是a[3]的内容,即数值4. 当然,我们还必须说明一个事实:数组下标是可以为负数的,实际上,取下标符“[ ]”的内部实现,就是指针运算!比如a[2],等价于(a+2),即以a地址为基址,取偏移量为2的地址的值。所以ptr1[-1]等价于(ptr-1)。
2、(int *)((int)a+1)
至于指针ptr2的处理更恶心一点。它先是把数组名a强制转换成整型变量,然后再加1,此时ptr2指向如下图所示:
![](https://ask.qcloudimg.com/http-save/yehe-5426759/fswxxsdgh1.jpeg?imageView2/2/w/1620)
显然,此时打印的内容就是ptr2所指向的往后4个字节的内容了,也就是a{0}的后三个字节和a[1]的第一个字节
要把上图中每一个字节的内容都打印出来没问题,但要知道字节序的概念,字节序分两种,一种叫大端 字节序(big-endian) ,当然除此之外必然有小端字节序(little-endian) ,让我们用一个问题,来引出字节序的概念,然后再来搞定这两个小鬼吧!
问题是这样的:对多字节存储的变量,机器是如何做出解释的??请看下图:
![](https://ask.qcloudimg.com/http-save/yehe-5426759/rro6vmn90i.jpeg?imageView2/2/w/1620)
假如这是一个普通的int变量,在32机器上int占用4个字节存储数据,就像上图中显示的那样,在4个字节中放置了一堆数字,但是机器究竟会把这个数解释成0x0103070E(大端模式)呢,还是解释成0x0E070301(小端模式)呢?答案是:都有可能!
官方解释: 1、所谓大端(big-endian)序,就是高优先位 对应高有效位 。 2、所谓小端(little-endian)序,就是高优先位 对应低有效位 。
民间解释: 1、所谓大端(big-endian)序,就是读取或者存放数据时,最低 位 对应 高地址 。 2、所谓小端(big-endian)序,就是读取或者存放数据时,最低 位 对应 低地址 。
回到原来的问题,此时ptr2指向了a[0]的第二个字节。我们以x86平台为例(小端序),此时其内部数据分布是这样的:
![](https://ask.qcloudimg.com/http-save/yehe-5426759/gm3l94j1gw.jpeg?imageView2/2/w/1620)
由于x86平台是小端序的,根据咱刚刚讨论过的理论,小端序的存取时最低位对应低地址 ,因此将会打印出0200 0000,如果题目中没有说明在x86平台,那答案是不确定的,取决于具体的平台,例如ARM平台就是大端序的。
大端模式:00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 0x10000
小端模式:01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 0x2000000
内存: -------------------------------->>
参考:
https://mengchao.xyz/index.php/archives/328/
https://cloud.tencent.com/developer/article/1638005