【问题标题】:modified a constant again.. with void pointers [duplicate]再次修改了一个常量..用空指针[重复]
【发布时间】:2010-10-09 17:10:58
【问题描述】:

可能重复:
Modified a constant in c

const int z = 420;
const void *v;
v = &z;

printf("\n%d | %d",z,*(int *)v);
//420 | 420

printf("\n%d | %d",*(char *)&z,*(char *)v); //0th-Bit same value
//-92 | -92

printf("\n%d | %d",*((char *)&z+1),*((char *)v+1) );    //1st-Bit same value    
//1 | 1

/***********************************************/
*((char *)&z+1) = 21;   //I change value for the 1st-Bit
                            //see v is not touched here.

printf("\n%d | %d -(note)-successfully corrupted (z+1) and change reflected in (v+1)",*((char *)&z+1),*((char *)v+1) );
//21 | 21
//yes  change is reflected in v after corruption of z

/****************the problem******************/

printf("\n%d | %d",z,*(int *)v);    //but now value of v is courrupt...while that of z is same
//420 | 5540
printf("\n%u | %u",&z,v);               //same address different values?
//1310548 | 1310548


/*************additional info*******************/

printf("\n%d | %d",*(&(*(&z+1))-1),*(int *)v);
//5540 | 5540

printf("\n%u | %u",(&(*(&z+1))-1),v);
//1310548 | 1310548

1>

指向“z”的空指针

当取消引用时会给出损坏的值

但是当直接使用 z 时,它会给出原始值。

所以同一个地址有 2 个不同的值

2>

当 z 经受恒等指针变换时

(即递增和递减)

z 现在将输出损坏的值!

但是 z 在进行正常或不进行转换时

like "*(&z)" 仍然会给出原始值。

【问题讨论】:

  • 正如 Michael Burr 在回复 your earlier question 时解释的那样,在 C 中修改 const 限定的对象会导致未定义的行为。如果已知对象不会更改,编译器可以执行一些优化,并且您看到的结果很可能是由于这些优化。您可以通过查看编译器生成的代码来找出答案。
  • 这是用 void 指针完成的......无论如何,是的,它是未定义的,我明白了......仍然必须有一些编译器专家在那里,谁可以解释为 y 相同的地址包含2 个不同的值...
  • 编译器知道z 的值将始终为420,因为您通过const-qualifying z 这么说。我猜当你稍后printf("%d", z) 时,编译器会发出将数字420 推送到堆栈上的代码,这样它就可以避免对z 的内存引用;您可以通过查看编译器为该程序生成的汇编代码来了解是否是这种情况。
  • 所以你是在暗示编译器保留 2 个常量副本?
  • 我没有暗示什么。我的意思是,如果您真的想知道在这个未定义行为的特定实例中会发生什么,您需要查看编译器生成的程序集。

标签: c pointers segmentation-fault constants


【解决方案1】:

如果您确实想防止数据被修改,请使用您的操作系统将其内存页声明为不可修改。

C 和 C++ 中的const 是概念上的安全机制和弱验证工具,而不是安全措施。它为遵循某些规则的程序员提供保证。如果违反规则,则无法保证。 (取决于严重程度,不保证它不会崩溃。允许您的程序崩溃或为“常量”提供不一致的值。)

哦,您真正的问题是地址中如何“存在”两个不同的值。答案是,如果编译器确定它知道您指的是常量,它不会查看地址而只是给出值。毕竟,这就是你应该说的没关系。

【讨论】:

  • 它不像我想要一些安全的东西......我的问题是 1 个地址如何存储不同的值......以及为什么指针运算会有所不同,实际输出哪个值。跨度>
【解决方案2】:

别再问这个问题了;-)

如果有帮助,您可以假设编译器采用了如下代码:

const int z = 420;
...
printf("%d\n", z);

并将其替换为:

const int z = 420;
...
printf("%d\n", 420);

这不能保证,你不能依赖它,但这是编译器所做的事情,它会解释你所看到的。

您还获取了z 的地址,但编译器不会/不一定会跟踪该指针的使用,并以相同的方式替换所有通过它的访问。这比仅仅识别符号 z 指的是一个 const 对象要困难得多。因此,当您无效地修改该 const 对象时,未定义行为的表现方式之一就是您所看到的不一致。

如果您想知道您的编译器实际上做了什么,并且您不会遵循 James 的建议,那么您就不走运了。这里没有人确切地知道你的编译器做了什么。甚至没有人知道您使用的是什么编译器。不同的编译器做不同的事情。

【讨论】:

  • compiler visual studio...无论如何,常量是内联的...这可能是解决方案...。引用:“关键字 const 不会将变量转换为常量!带有的符号const 限定符仅表示该符号不能用于赋值。这使值通过该符号只读;它不会阻止通过程序内部(甚至外部)的某些其他方式修改值。它是仅在限定指针参数时非常有用,以指示此函数不会更改参数指向的数据,但其他函数可能会。"
  • @bakra:我不知道那句话出自哪里。我不认为这一切都是真的。就合法的 C 语法而言,在 int 变量上使用 const 并不会正式将变量转换为常量。因此,您不能将其用作switch 语句中的案例。但是,它确实允许编译器使用值不变的“事实”来优化程序(假设它也不是volatile)。那是因为任何试图改变它的程序无论如何都有未定义的行为,所以优化是否“破坏”它并不重要。
猜你喜欢
  • 1970-01-01
  • 2019-03-07
  • 1970-01-01
  • 2014-02-23
  • 2023-03-15
  • 2014-02-04
相关资源
最近更新 更多