2015-05-01 71 views
3

我正在读这本书http://publications.gbdirect.co.uk/c_book/chapter8/const_and_volatile.html,我停下了其中一个例子。在我看来这是不正确的。我认为,没有不确定的行为。我错了吗?在这里它是:误解代码示例

隔空类型的数据对象,它是不常量和 的将其放入一个指向同一 类型的常量限定版本的地址是既安全又明确允许;你将能够使用 指针来检查对象,但不能修改它。把 一个const类型的地址放到一个指向非限定类型的指针上会更危险,因此被禁止(尽管你可以通过使用强制类型来得到 )。下面是一个例子:

#include <stdio.h> 
#include <stdlib.h> 

main(){ 
     int i; 
     const int ci = 123; 

     /* declare a pointer to a const.. */ 
     const int *cpi; 

     /* ordinary pointer to a non-const */ 
     int *ncpi; 

     cpi = &ci; 
     ncpi = &i; 

     /* 
     * this is allowed 
     */ 
     cpi = ncpi; 

     /* 
     * this needs a cast 
     * because it is usually a big mistake, 
     * see what it permits below. 
     */ 
     ncpi = (int *)cpi; 

     /* 
     * now to get undefined behaviour... 
     * modify a const through a pointer 
     */ 
     *ncpi = 0; 

     exit(EXIT_SUCCESS); 
} 

例8.3 如示例所示,也可以取为恒定的对象的地址,>生成的指针 到非恒定,然后使用新指针。这是您的 程序中的错误,并导致未定义的行为。

在此示例中,ncpi最终指向i而不是ci。所以我认为这使得这个例子不正确—在通过指针修改非const变量时没有未定义的行为。你同意吗?

+1

你为什么会认为修改一个常量不是未定义的东西? –

+2

我不知道。因为在这个例子中ncpi最后指向了我的位置,没有ci。所以我认为这使得这个例子不正确。你同意吗? –

+0

请注意,如果你的问题提示“如果你的问题是”ncpi“最终指向”i“,而不是”ci“,那么你的问题会得到更好的回答,而且没有人会拖延错误路径。所以我认为这就是这个例子不正确,你同意吗?“ –

回答

-2

它未定义,因为它可能存储在只读存储器中。在x86系统中情况并非如此,但是在这里我们遇到了很多其他问题,如启用大量优化时出现的别名问题。无论哪种方式,即使只是直观地说,为什么你会认为通过一个指向编译器不能静态验证的指针来修改const将是安全的?

+1

最后ncpi指向我的位置,而不是ci。 ! –

4

我同意这是一个有缺陷的例子。代码本身展现出定义的行为。

最终作业前的注释*ncpi = 0;与代码不一致。可能作者打算做一些不同的事情。


我的第一个反应是如同代码改写一个const:     我已经修改了我的答案。

+1

它不会改变恒定的ci值,因为最后ncpi指向我的位置,而不是ci。这没有任何意义(我正在谈论这本书中的例子)。 –

+0

@KarolisMilieška:你说的没错。我*假设代码试图写入常量。也许作者认为它也是如此,这就是为什么他/她的结论是书面的。评论当然说代码是写给一个'const'的。 – wallyk

+2

@wallyk:你不必保留所有原始文本的删除线。它只是降低了信噪比,并没有真正帮助答案。你可以继续前进并删除它(尽管你可以保留评论指出你的第一个反应是错误的;好奇的人可以检查修订历史的答案)。 – Cornstalks