能否将unsigned long long变量用作地址?硬件与C语言特性疑问
关于unsigned long long当作指针使用的疑问
我尝试将unsigned long long变量当作地址使用,测试后发现似乎可行:
int var = 0; // 当前系统中var的地址为0x7fffffffe4a4 unsigned long long ull = 0x7fffffffe4a4; scanf("%d", ull); // 尝试用ull作为var的地址为其赋值 printf("%d\n", var); // 看起来成功了!
我还进行了如下实验:
int var = 0; // 当前系统中var的地址为0x7fffffffe4a4 unsigned long long ull = 0x7fffffffe4a4; int *ptr = &var; // 先确认unsigned long long与指针的内存占用是否不同 printf("%zu\n", sizeof(ull)); printf("%zu\n", sizeof(ptr)); // 我的系统中结果均为"8" // 再通过两种方式为var赋值 scanf("%d", ull); // 尝试用ull作为地址为var赋值 printf("%d\n", var); scanf("%d", ptr); // 同时用常规指针为var赋值 printf("%d\n", var); // 结果符合预期!
虽然编译器警告参数应为int*而非unsigned long long,但unsigned long long变量似乎可成功用作指针。我有以下疑问:
- 硬件层面,变量与指针有何区别?
- 这两种类型的对象在存储和使用时是如何被处理的?由谁处理?
- 是否推荐执行上述操作?
- 这是否属于C语言的特性?
问题解答
1. 硬件层面,变量与指针有何区别?
在硬件层面没有本质区别——它们都是内存里存储的一串二进制数值。差异只在于CPU对它们的解读逻辑:
- 普通变量(比如
int、unsigned long long)的数值会被当作数据处理,比如参与算术运算、直接输出。 - 指针的数值会被当作内存地址,CPU会根据这个数值去访问对应的内存单元,读取或写入该地址的数据。
2. 这两种类型的对象在存储和使用时是如何被处理的?由谁处理?
- 存储阶段:不管是
unsigned long long还是指针,都是按自身字节长度(比如你系统里的8字节)存在内存中,存储的都是二进制数,硬件上没有区别,由操作系统负责分配内存空间。 - 使用阶段:区别由编译器和CPU共同处理:
- 编译器编译时会根据变量类型生成不同指令:对指针生成内存访问指令(比如
mov的间接寻址),对unsigned long long生成普通数值操作指令。 - 你直接把
unsigned long long传给scanf时,编译器会发出类型不匹配警告,但最终生成的指令还是把这个8字节数值当作地址传给了函数,而scanf内部只是把它当作地址写内存,所以碰巧能运行。
- 编译器编译时会根据变量类型生成不同指令:对指针生成内存访问指令(比如
3. 是否推荐执行上述操作?
绝对不推荐,核心原因有三个:
- 类型不安全:编译器无法做类型检查,要是传了一个非法的
unsigned long long值,程序会直接崩溃或出现不可预料的行为(比如修改了系统内存)。 - 平台兼容性差:不是所有平台上
unsigned long long和指针长度都一致,比如32位系统中指针是4字节,unsigned long long是8字节,强行使用会导致地址截断,直接出错。 - 代码可读性差:其他开发者看到用
unsigned long long当指针,会完全摸不着头脑,维护成本极高。
正确做法是用标准指针类型,或通过显式强制转换:scanf("%d", (int*)ull);——但即使是显式转换,也要确保数值是合法的内存地址。
4. 这是否属于C语言的特性?
这不是C语言的特性,只是特定平台下的“巧合行为”:
- C语言明确要求指针和整数类型之间的转换必须显式强制转换,直接把整数传给需要指针的参数属于未定义行为。
- 你的测试能成功,只是因为64位系统上
unsigned long long和指针长度相同,编译器生成的指令刚好能把这个整数当作地址用,但这完全依赖平台,不是C语言标准保证的行为。
内容的提问来源于stack exchange,提问作者Ubgreat
相关产品推荐
相关产品推荐

