1

嗨,我是编程世界的初学者,我想知道如何避免更改 const 变量的值。

#include <stdio.h>
int main()
{
 const int i = 10;
 int * p = &i;
 *p = 20;
 printf("*p = %d\ni = %d\n", *p,i);
 printf("%u\n%u\n",&i, p);
 return 0;
}

在上面的程序中,当我通过指针为 const 字段分配值时,我只收到警告但没有错误,但是当我打印出来时并没有什么不同:

*p = 20
i = 10
3210723532
3210723532

那么,当指针无法更改时,获取指向 const 的指针有什么用。

4

4 回答 4

7

首先,编译器会因为代码给出警告int * p = &i;

并且 i 的值没有改变,因为编译优化了代码,我使用 gcc 来测试代码:

如果我使用gcc -O0 const.c -o const,O0表示没有编译器优化,结果是

*p = 20
i = 20
1114013412
1114013412

但是当我使用gcc -O2 const.c -o const,O2代表编译器优化时,结果是

*p = 20
i = 10
1262279764
1262279764

因此,编译器知道iis的类型const,并在编译时替换i10,因此代码变为

 printf("*p = %d\ni = %d\n", *p,10);

您也可以使用gcc -S const.c查看汇编代码。

于 2012-04-10T09:31:23.077 回答
2

C 语言标准(几乎)从不要求编译器拒绝不正确的代码。如果你写了一些非法的东西,而编译器只是警告你,就 C 语言标准而言,编译器已经完成了它的工作。

您需要非常认真地对待编译器警告。如果您的代码在没有警告或错误的情况下编译,那么它可能是合法的(这并不意味着它会真正起作用!)。

于 2012-04-10T09:17:50.577 回答
1

C 标准仅使用术语“诊断”。警告和错误之间没有区别。

没有强制转换的const int *to转换int *是需要诊断的约束违规。

这将其与语法错误归为同一类别:您的代码不是有效的 ISO C 程序,并且如果它被翻译并执行,则行为未定义。

不幸的是,许多编译器没有将所需的诊断与他们添加的额外诊断区分开来,更糟糕的是,他们有时需要将诊断作为警告。这是允许的:C 标准没有规定必须阻止需要诊断的程序翻译和执行。通过发出警告,编译器满足诊断要求,仅此而已。

另一个问题是,许多 C 编译器甚至不接受标准的 ISO C 方言,除非他们被要求,而是接受他们自己的方言,这些方言可能有不符合标准(即不向后兼容)的扩展。

GNU C 编译器可以理解一种称为 GNU C 89 的 C 方言,如果你不给它任何方言选项的话。

const int *因此,具有讽刺意味的是,在这种方言中,转换为没有演员表只是一个警告int *,而某些合法的 C90 程序则被完全拒绝。

所以基本上你总是必须了解如何控制编译器的输入方言,并跟进所有你必须自己理解的警告,无论它们是真正违反语言,还是只是编译器的突发奇想writers(“建议在这个表达式周围加上括号”)。

编译不是一个坏主意gcc -Wall -W -ansi(如果您在 C90 中编程;或者-std=c99代替ansiC99)并确保没有警告。甚至那些建议额外括号之类的文体也没有。如果您没有足够的纪律来跟进警告,请添加-Werror将它们变成使您的构建失败的错误。有些人还会推荐-pedantic

如果你遵循这个原则,a 的颠覆const int就不会潜入你的代码库。

于 2012-04-10T10:40:15.230 回答
0

改成一个#define

声明的对象const在该术语的英文含义中不是恒定的,它们是“只读的”。

#include <stdio.h>
int main()
{
 #define I 10
 int * p = &I; // illegal &I
 *p = 20;
 printf("*p = %d\nI = %d\n", *p,I);
 printf("%u\n%u\n",&I, p); // illegal &I
 return 0;
}
于 2012-04-10T09:32:29.403 回答