const int * ptr = 500;它存储的确切位置

时间:2017-04-21 05:32:35

标签: c linux const

我知道,在const int *ptr我们可以更改地址但不能更改值。即,ptr将存储在读写部分(堆栈)中,并且对象或实体将存储在数据分段的只读部分中。因此,我们可以更改指针ptr指向的地址,但不能更改常量的对象。

int main()
{
  const int *ptr=500;
  (*ptr)++;
  printf("%d\n",*ptr);
}

输出是将只读位置分配给* ptr

int main()
{
  const int *ptr=500;
  ptr++;
  printf("%d\n",*ptr);
}

没有编译错误,但在运行时输出是“分段错误”。

我同意第一个问题。为什么我在第二个问题中遇到分段错误?它们究竟存放在哪里?

3 个答案:

答案 0 :(得分:5)

分段错误的原因与您的想法不同。

因为const

这是因为在执行*ptr

时,您不能访问您尝试访问的区域

当您指向“某事”时,仍然不允许您访问数据(也就是取消引用指针),直到您将指针指向属于您的某些内存为止。

示例:

int x = 0;
int* p = (int*)500;

int a = *p;  // Invalid - p is not pointing to any memory that belongs to the program

p = &x;
int b = *p;  // Fine - p is pointing to the variable x

p++;
int c = *p;  // Invalid - p is not pointing to any memory that belongs to the program

“无效”代码可能会产生分段错误。另一方面,它也可能只是执行并产生意外结果(甚至更糟:产生预期结果)。

答案 1 :(得分:1)

 const int *ptr=500; // WRONG

这声明了一个局部变量,它是一个指向某个常量整数的指针。 const只告诉编译器不允许更新(覆盖)解除引用的指针存储单元。

但是,您的代码不正确;你可能想要:

const int *ptr = (const int*)500;

指针初始化为address 500(初始化指针)。

在大多数系统上,该地址(以及以下的地址,例如sizeof(int)以来的地址504为4)不在virtual address space之内。因此取消引用它(*ptr)是undefined behavior,并且通常会提供一些segmentation fault。另请参阅this

  

ptr将存储在读写部分(堆栈)中,对象或实体将存储在数据段的只读部分。

这是错误的。在编译时没有做任何事情来将内存区域保持为只读text segment(但是,大多数编译器在编译时将大多数文字或const静态或全局数据定义在其中) 。只是你禁止编译器更新指向的东西(没有强制转换)。

如果在运行时需要只读内存区域,则需要向操作系统询问(例如在Linux上使用mmap(2)& mprotect(2))。 BTW保护适用于pages

在Linux上,使用pmap(1)(或proc(5),例如从您的程序中顺序读取伪文件/proc/self/maps。您可能想要添加

char cmdbuf[64];
snprintf(cmdbuf, sizeof(cmdbuf), "pmap %d", (int) getpid());
system(cmdbuf);
在代码中ptr取消引用之前

,以了解其虚拟地址空间是什么。

尝试

cat /proc/self/maps

cat /proc/$$/maps

并了解他们的输出(请注意$$已扩展到shell的pid)。也许在你的错误程序(你应该用gcc -Wall -g编译)上试验strace(1)

答案 2 :(得分:1)

这里有很多混乱。

  

并且对象或实体将存储在数据分段的只读部分

不,不需要存储指向对象的位置。这仅在声明指向对象时由conststatic等任何限定符/说明符确定。

  

const int * ptr = 500;

这不是有效的C,代码必须产生编译器消息。无法将整数赋给指针,两者之间必须有转换。 GCC在这里有一个已知的缺陷,你必须将它配置为标准编译器。 gcc -std=c11 -pedantic-errors

如果您的代码如const int *ptr=(int*)500;是有效的C,那么它会将指针设置为指向地址500.如果地址500处有int,代码将正常工作。如果没有你可以访问的内存,那么你会得到一些实现定义的行为,比如崩溃 - 内存映射超出了语言的范围。

  

(* PTR)++;

这不是有效的C,代码必须产生编译器消息。您不能修改只读位置。

总的来说,您的编译器配置似乎很差。正确配置的GCC会产生2个编译器错误。