我只是想知道我们是否可以在运行时跳过分段错误并在内存位置写入NULL。截至目前,我相信它是一个非常神圣不可侵犯的地方,你不能在那里做任何事情。我尝试了一小段代码。
#include<iostream>
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
using namespace std;
int main()
{
int *p = NULL;
int z=6;
p= &z;
std::cout << "value of p is :" << *p;
p=NULL;
*p=5; // Will give segmentation fault as dereferencing of NULL is not allowed
std::cout << "value of p is :" << *p;
getch();
return 0;
}
我知道取消引用NULL内存分配是不可能的,因此无法分配任何值。这样做会给我们分段错误。只是为了一个好奇的本性,如果我们可以欺骗并写入NULL?
答案 0 :(得分:6)
在典型的现代系统中,实际上存在 no 内存映射到虚拟地址0。它根本就不存在。当您尝试写入地址0时,CPU本身就会引发分段错误。
物理地址0,但现代操作系统具有虚拟内存映射,为每个进程提供自己的自定义地址空间。该地址空间不包含虚拟地址0的映射。
答案 1 :(得分:3)
这不是编译器阻止你这样做的,它是你的操作系统。
考虑使用C代码
int main(int argc, char *argv[])
{
int* p = 0;
*p = 42;
return 0;
}
编译器在ASM中将其转换为类似的内容
.file "test.c"
.def ___main; .scl 2; .type 32; .endef
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $16, %esp
call ___main
movl $0, 12(%esp)
movl 12(%esp), %eax
movl $42, (%eax)
movl $0, %eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE0:
通知
movl $42, (%eax)
该指令尝试将42写入%eax指向的位置,该位置设置为0以上。
据我所知,如果你正在使用虚拟内存,你的应用程序的位置0不是真实内存中的位置0。我已经读过某个地方,bootloader会将内容写入内存的开头或类似内容,但我可能在这里错了。
答案 2 :(得分:2)
好吧,你可以尝试这样做,而且根据编译器,操作系统等,你甚至可以逃脱它,并在那里存储一些东西(“那里”真的存在)。
然后,您的程序可能会因访问冲突而关闭,或者int可能会格式化您的硬盘驱动器,或者如果它连接到正确的硬件这样做,您的计算机可能会发射一些核导弹......
答案 3 :(得分:2)
如果操作系统允许您在地址零处映射某些内容,则可以取消引用NULL指针而不会出现问题。或者,您可以修改编译器和/或标头,以便NULL具有除了所有零位之外的某些值(向指针投射整数零不必产生按位为零的值)。然后你可以在NULL映射到的地址上映射一些东西,它可以工作。
答案 4 :(得分:1)
不,你不能,不,你甚至不应该尝试!如果您这样做,最终会得到未定义的行为。
当指针成为NULL
时,它只是意味着它指向无效的东西,这是无意义的东西。
所以你不能告诉编译器指向无效的东西,然后尝试在那里保存有意义的东西,它根本没有任何意义。
答案 5 :(得分:1)
没有可移植的方法可以做到这一点(如果你问我也是好事)
某些平台可能允许它(通常是那些没有MMU的平台),但如果您甚至不尝试禁用MMU,那么从长远来看,您会更开心。 NULL指针引用导致错误的原因,通常更好地知道您的指针设置为NULL(或可能未初始化),而不是忽略它并继续前进。
想象一下例如malloc()无法分配内存并尝试使用它而不进行检查的情况。你可能想知道。
答案 6 :(得分:1)
我可能在这里错了,但我认为编译器 允许你取消引用NULL - 毕竟,SIGSEGV是一个在运行时期间杀死程序的信号。编译器正在编译代码,但操作系统内存管理不允许程序使用0x0的内存内容。
也许这是由编译器链接的一些库处理的,即使当前计算机实际允许,也可能拒绝让您访问0x0。
我猜你可能会走进一个允许使用0x0的系统,但它已经被用了很长时间来表示系统库或操作系统可能拒绝的“无效位置”,以避免使用NULL检查破坏代码。