#include <stdio.h>
int main(void){
unsigned a[3][4] = {
{2,23,6,7},
{8,5,1,4},
{12,15,3,9}
};
printf("%u",*((int*)(((char*)a)+4)));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我的机器中的输出是a[0][1]即23的值.可以有人解释这是如何工作的?
编辑:回滚到旧yucky代码,确切地呈现给我:P
GMa*_*ckG 13
所以你把你的数组放在内存中:
2, 23, 6, 7, 8...
Run Code Online (Sandbox Code Playgroud)
这样做是将数组转换为a char*,它允许您访问单个字节,它指向这里:
2, 23, 6, 7, 8...
^
Run Code Online (Sandbox Code Playgroud)
然后它添加四个字节,将其移动到下一个值(稍后将详细介绍).
2, 23, 6, 7, 8...
^
Run Code Online (Sandbox Code Playgroud)
然后它将它变成一个int*并取消引用它,得到值23.
这个代码在技术上有三个问题.
第一个是它假设a的unsigned大小为4个字节.(因此+ 4).但这不一定是真的!+ sizeof(unsigned)不管unsigned发生什么样的规模,都会更好,确保正确性.
第二个问题是转换为int:原始数组是unsigned,但值正在转换为int.在unsigned范围内存在int无法表示的值(因为在int范围的一半中是负数.)因此,如果数组中的某个值不能表示为int(意味着值大于INT_MAX),则会得到错误的价值.更好的是转换为unsigned*,以保持正确的类型.
最后一件事是格式说明符.整数的说明符是%d,但代码使用%u,用于无符号整数.实际上,即使重新投入int*是错误的,printf也会将该值重新投入到unsigned*恢复中,恢复它的完整性.通过解决问题二,问题三解决了问题.
有一个隐藏的第四个问题:代码很糟糕.这可能是出于学习目的,但是很糟糕.
数组:
unsigned a[3][4] = {
{2,23,6,7},
{8,5,1,4},
{12,15,3,9}
};
Run Code Online (Sandbox Code Playgroud)
在内存中布局为(假设a它本身位于内存位置0x8000,特定字节序和四字节int):
0x8000 0 0 0 2
0x8004 0 0 0 23
0x8008 0 0 0 6
0x800C 0 0 0 7
0x8010 0 0 0 8
0x8014 0 0 0 5
0x8018 0 0 0 14
0x801C 0 0 0 12
0x8020 0 0 0 15
0x8024 0 0 0 3
0x8028 0 0 0 9
Run Code Online (Sandbox Code Playgroud)
打破表达方式:
*((int*)(((char*)a)+4))
Run Code Online (Sandbox Code Playgroud)
((char*)a)给你一个char指针.+4将指针前进4个字节(4 * sizeof(char))(int*)将其结果转换为int指针.*取消引用指针提取int.这是一种非常愚蠢的方式,因为它本质上是不可移植的(int例如,对于两个或八个字节的环境).
| 归档时间: |
|
| 查看次数: |
659 次 |
| 最近记录: |