免责声明:我是 C/C++ 的新手。
如果我要手动将内存地址分配给C 中的变量,然后尝试回显该值……我是否可以不受限制地访问内存中的任何内容,或者是否存在限制?
例如:
char * p = (char *)0x28ff44;
printf("Memory value: %c", *p);
我猜如果该地址的内容不适合 char 类型的大小,那将会严重崩溃,但这只是一个示例。我真正好奇的是,如果这样的事情是可能的,或者操作系统是否施加限制并且只允许您访问给定内存空间中的内存?
免责声明:我是 C/C++ 的新手。
如果我要手动将内存地址分配给C 中的变量,然后尝试回显该值……我是否可以不受限制地访问内存中的任何内容,或者是否存在限制?
例如:
char * p = (char *)0x28ff44;
printf("Memory value: %c", *p);
我猜如果该地址的内容不适合 char 类型的大小,那将会严重崩溃,但这只是一个示例。我真正好奇的是,如果这样的事情是可能的,或者操作系统是否施加限制并且只允许您访问给定内存空间中的内存?
哦,天哪,好吧。
从技术上讲,是的,你可以。在不使用 MMU 或任何形式的保护(或者,您知道,实模式下的 x86)的嵌入式设备中,您可以完全按照您在此处发布的内容进行操作。您也可以在任何操作系统上以用户模式执行此操作,但您实际访问有效内存的机会非常小。
实际上,不,你不能那样做。考虑到虚拟内存和内存保护,您尝试访问的区域很可能没有被映射,因此会失败。此外,如果您访问受保护的内存(例如属于操作系统的任何内容),您的访问将失败。这两种情况都是导致分段错误的原因。
您的声明是有效的(对于有效的不同定义),程序将尝试访问您请求的内存。只是它实际上可能没有映射到任何东西。
还值得注意的是,这就是内存映射 I/O 的工作方式。假设我有一个硬件控制寄存器,当写入它时,它会在附加的 UART/串行线路上写入一个字节(并且,为简单起见,它就像魔术一样工作,不需要设置任何其他寄存器)。在 C 中,对于我过于简化的设备,这将被编写如下:
#define UART1_OUT 0xFC56
volatile char* uart = UART1_OUT; // Definition of pointer to variable.
// volatile is required here. Look it up, but
// it basically stops your compiler optimising
// anything to do with this variable
*uart = 'A'; // Write an A character to the serial line
当然,现实世界的设备要复杂一些;)。
具有内存管理单元 (MMU) 的系统很可能不允许您访问任意内存。任何现代操作系统都使用内存保护。但是在嵌入式领域,有许多操作系统没有采用内存保护,并且确实可以访问任何可寻址的内存。
如果我要手动将内存地址分配给 C 中的变量,然后尝试回显该值...我是否可以不受限制地访问内存中的任何内容,或者是否存在限制?
C 语言很乐意让您尝试这样做,但大多数操作系统不允许您访问进程内存空间之外的内存。如果您正在为嵌入式系统编写代码,而您的代码和硬件之间没有太多的联系,那么您可能能够从您喜欢的任何位置读取和写入。但是,如果您正在为具有受保护内存的系统编写代码,那么就没有那么多了。
我猜如果该地址的内容不适合 char 类型的大小,那将会严重崩溃
不...编译器不关心在任何给定地址存储什么类型的数据。当你说(char *)0x28ff44
你告诉它0x28ff44
是 achar *
时,这对编译器来说已经足够好了。但是,您的代码可能仍会因其他原因而崩溃,例如 if0x28ff44
不是有效地址。