我想将一些值(比如2345)分配给一个内存位置(比如0X12AED567)。可以这样做吗?
换句话说,我该如何实现以下功能?
void AssignValToPointer(uint32_t pointer, int value)
{
}
答案 0 :(得分:15)
你问这个问题的事实表明你已经过了头脑。但是你走了:
*(int *)0x12AED567 = 2345;
答案 1 :(得分:3)
答案取决于一些因素。您的程序是否在现代操作系统中运行?
如果是,尝试访问未映射的内存区域将导致SIGSEGV
。要实现这一点,您必须使用特定于系统的函数来映射包含此确切地址的内存区域,然后再尝试访问它。
答案 2 :(得分:2)
将内存位置视为指针
int* pMemory = OX12AED567;
*pMemory = 2345;
注意:只有当您的程序可以访问和写入该内存位置时,这才有效。写入这样的任意内存位置本质上是危险的。
答案 3 :(得分:2)
就C而言,这是未定义的行为。我的以下建议也是未定义的行为,但避免了所有基于类型和基于别名的问题:使用字符。
int a = get_value();
char const * const p = (const char * const)&a;
char * q = (char *)0x12345;
memcpy(q, p, sizeof(int));
或者,您可以直接访问字节q[i]
。 (这是UB的部分:指针q
不是作为实际对象的地址获得的,也不是作为分配函数的结果获得的。有时这是正常的;例如,如果你正在写一个免费的在实模式下运行并访问图形硬件的程序,您可以直接在一个众所周知的硬编码地址写入图形存储器。)
答案 4 :(得分:1)
您已经指出,该地址是一个物理地址,并且您的代码正在一个过程中运行。
所以,如果你是
在某种高级操作系统中,例如Linux,你必须得到一个映射到物理地址空间。在Linux中,/ dev / mem会为您做到这一点。
在内核中或没有操作系统且使用MMU时,您必须将物理地址转换为虚拟地址。在Linux内核中,phys_to_virt()为您做到了这一点。在内核中,我假设,这个地址总是被映射。
在内核中或没有操作系统且没有MMU的情况下,直接写入该地址。根本没有可以考虑的映射。
现在,您有一个有效的映射或物理地址本身,您传递给您的函数。
void AssignValToPointer(uint32_t pointer, int value)
{
* ((volatile int *) pointer) = value;
}
您可能希望添加volatile关键字,因为如果您之后没有从该位置读取(可能是写入内存映射硬件的寄存器的情况),编译器可能会优化写操作。
您可能还想使用uintptr_t数据类型而不是uint32_t作为指针。
答案 5 :(得分:1)
C99标准草案
如果没有实现定义的行为,这可能是不可能的。
关于演员表:
*(uint32_t *)0x12AED567 = 2345;
C99 N1256 standard draft" 6.3.2.3指针"表示:
5整数可以转换为任何指针类型。除非事先指明,否则 结果是实现定义的,可能没有正确对齐,可能不指向 引用类型的实体,可能是陷阱表示。 56)
GCC实施
GCC将其int指向以下的指针实现:https://gcc.gnu.org/onlinedocs/gcc-5.4.0/gcc/Arrays-and-pointers-implementation.html#Arrays-and-pointers-implementation
如果指针表示小于整数类型,则从整数到指针的强制转换丢弃最高有效位,如果指针表示大于整数类型,则根据整数类型的符号扩展,否则位不变。
所以演员阵容将按预期为此实施工作。我希望其他编译器能做类似的事情。
答案 6 :(得分:0)
条件是它不便携或安全(根本):
*((int *)0x12AED567) = 2345;