繁体   English   中英

内存地址可以在 C 中移植吗?

[英]Are memory addreses portable in C?

假设我们有程序 1...

./程序1

int main(int argc, char *argv[])
{
  int *i;
  *i = 10;
  printf("%lld", i);
  return 0;
}

现在程序2...

./program2 program1output 10

int main(int argc, char *argv[])
{
  int *t;
  t = (int*)atoll(argv[1]);
  *t = atoi(argv[2]);
  return 0;
}

这会起作用吗? 你可以在不同的程序之间共享内存地址吗?

这种行为不是由 C 标准定义的。 在任何通用多用户操作系统上,每个进程都有自己的虚拟地址空间。 除了某些共享内存外,分配给进程的所有内存都与分配给其他进程的内存分开:

  • 只读数据可能会在进程之间共享,尤其是运行同一可执行文件的两个进程的指令和常量数据以及共享库的指令和常量数据。 该数据可能在不同的进程或不同的地址中具有相同的地址(取决于各种因素,包括代码是否与位置无关以及是否使用地址空间布局随机化)。
  • 默认情况下,一些操作系统还将系统范围的共享数据映射到进程中。
  • 通过显式请求进程映射共享内存段,可以在进程之间共享内存。 这些段可能会或可能不会出现在不同进程中的相同虚拟地址处。 (映射共享内存的请求可能会请求某个地址,在这种情况下,不同的进程可以安排使用相同的地址,也可以让映射软件选择地址,在这种情况下,不同的进程不能依赖于接收相同的地址分配.)

在专用操作系统中,不同的进程可以共享一个地址空间。

补充

这不是正确的代码:

int *i;
*i = 10;

声明int *i; i定义为指针,但不为其分配值。 然后使用*i是不合适的,因为它试图引用i指向的位置,但i没有被分配指向任何东西。

要定义一个int并使其地址在输出中可见,您可以定义int i; 然后打印&i

这不是打印地址的正确方法:

printf("%lld", i);

要打印地址,请将其void *转换为void *并使用%p对其进行格式化。 格式化的结果是实现定义的:

printf("%p", (void *) &i);

这不是重建地址的好方法:

int *t;
t = (int*)atoll(argv[1]);

printf ,类型应该是void * ,并且尝试使用atoll进行转换时会出现问题。 C 标准不保证它会起作用; %p打印产生的格式可能不是正常的整数格式。 相反,将%p说明符与sscanf

void *temp;
if (1 != sscanf(argv[1], "%p", &temp))
    exit(EXIT_FAILURE);
int *t = temp;

当地址来自其他进程时, sscanf转换的行为不是由 C 标准定义的。

原则上,应用程序在其自己的/私有内存上运行。 有多种方法可以在不同的进程之间共享内存,但这需要特殊的机制来克服上述“主要”(例如内存映射文件)。 有在短期看,例如, 文章共享内存。

在您的情况下,程序一将结束并且其内存不再可用; 并且您访问它的方式绝对不是访问共享内存所需的“特殊机制”之一:

尽管整数值可以转换为指针值,但仅当整数值最初从指针转换为有效对象时,访问该指针才有效。 在您的示例中情况并非如此,因为在t = (int*)atoll(argv[1]);计算的积分值t = (int*)atoll(argv[1]); 从未指向当前程序中的有效对象。

通常,内存地址与进程相关联,因为每个进程可能有自己的内存空间。 因此,地址是虚拟地址而不是物理地址,这意味着它们是对进程内存空间中某个位置的引用,而不是对芯片上某个位置的引用。

(并非所有环境都有虚拟内存。例如,嵌入式系统可能没有。)

如果有两个程序在同一个进程中运行,则可以在它们之间传递一个指针。 例如,主程序可以传递一个指向它加载的动态链接库的指针。


暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM