改变C中的const值

时间:2010-09-14 13:57:55

标签: c++ c

我在以下代码片段中找到了

const int i = 2;  
const int* ptr1= &i;  
int* ptr2 = (int*)ptr1;  
*ptr2 =3;

i的值变为3.我想知道的是为什么允许这样做。这可能会有什么帮助?

9 个答案:

答案 0 :(得分:30)

这是允许的,因为你通过将它转换为非const指针来推翻ptr1的constness。这就是演员阵容非常危险的原因。

请注意,某些编译器(如GCC)不允许您像这样抛弃const状态。

答案 1 :(得分:12)

你通过玩指针技巧打破了恒定性保证。这不能保证一直工作,并且几乎可以调用任何行为,具体取决于您抛出它的系统/ OS /编译器。

不要那样做。

或者至少不要这样做,除非你真的知道自己在做什么,甚至理解它并不是最便携的。

答案 2 :(得分:10)

“允许”是“被阻止”的反对,但它也与“被禁止”相反。你已经看到修改你的const对象没有被阻止,但这并不意味着它是允许的。

在“允许”的意义上,修改const对象不是“允许的”。标准没有定义程序的行为(见6.7.3 / 5)。恰好在您的实现上,在该运行中,您看到了值3.在另一个实现或另一天,您可能会看到不同的结果。

然而,它并没有“被阻止”,因为C投射的方式工作,在编译时检测它是一个停滞的问题。在运行时检测它需要在所有内存访问中进行额外检查。该标准旨在不对实现施加大量开销。

完全支持抛弃const的原因,因为如果你有一个指向非const对象的const指针,那么该语言允许你(在两种意义上)修改该对象。为此,您需要摆脱const限定符。这样做的结果是程序员也可以从指向实际为const的对象的指针中丢弃const限定符。

这是一个(稍微愚蠢的)代码示例,它抛弃了const限定符,因为这个原因:

typedef struct {
    const char *stringdata;
    int refcount;
} atom;

// returns const, because clients aren't allowed to directly modify atoms,
// just read them
const atom *getAtom(const char *s) {
    atom *a = lookup_in_global_collection_of_atoms(s);
    if (a == 0) {
        // error-handling omitted
        atom *a = malloc(sizeof(atom));
        a->stringdata = strdup(s);
        a->refcount = 1;
        insert_in_global_collection_of_atoms(a);
    } else {
        a->refcount++;
    }
    return a;
}

// takes const, because that's what the client has
void derefAtom(const atom *a) {
    atom *tmp = (atom*)a;
    --(tmp->refcount);
    if (tmp->refcount == 0) {
        remove_from_global_collection_of_atoms(a);
        free(atom->stringdata);
        free(atom);
    }
}
void refAtom(const atom *a) {
    ++(((atom*) a)->refcount);
}

这很愚蠢,因为更好的设计是转发声明atom,使指针完全不透明,并提供访问字符串数据的功能。但是C并不要求你封装所有内容,它允许你返回指向完全定义类型的指针,并且它希望支持这种const用法来呈现一个“真正”可修改的对象的只读视图。 / p>

答案 3 :(得分:5)

const的确意味着“只读”。

正如您所知,const对象的值可能会发生变化,但您必须使用不正确的方法来执行此操作。在使用这些不正确的方法时,您可以调用未定义的行为

答案 4 :(得分:2)

它之所以有效,是因为你明确地将指针的const强制转换了。虽然ptr1是指向const int的指针,但ptr2是指向int的指针,因此它的指针是可更改的。

这样做的理由很少,但您可以找到避免代码重复的情况。例如:

const char* letter_at(char* input, int position)
{
    ... stuff ...
    return &found_char;
}

char* editable_letter_at(char* input, int position)
{
    return (char*)(letter_at(input, position));
}

(从有效C ++第3项的第3项中的C ++示例中略微损坏的示例)

答案 5 :(得分:2)

如果你要在C ++程序中抛弃constness,请使用更多的C ++样式:

int *ptr2 = const_cast<int*>(ptr1);

如果你遇到与这种类型的演员相关的问题(你会,你会这样做),那么你可以通过搜索“const_cast”而不是在阳光下尝试每个组合来快速找到它发生的位置。此外,它还可以帮助我们可能会或可能不会追随你的人。

只有少数几种情况我认为这有帮助。他们中的大多数是角落案件。如果你用C ++开发,我会不惜一切代价避免这种情况。

答案 6 :(得分:2)

C演员告诉编译器你知道自己在做什么,并确保它最终都能正常工作。如果你使用它们而不准确理解你正在做什么,你可能会遇到麻烦。

在这种情况下,编译器完全有权将i放入只读内存中,因此运行时此代码会崩溃。或者,它可能会像你看到的那样工作。标准将此指定为未定义的行为,因此字面上可能会发生任何事情。

C最初是为编写Unix而设计的,故意让程序员在操作数据方面有很大的自由,因为在OS编写中,编写高度特定于实现的代码通常非常有用,这些代码可以执行任何不安全的操作。其他背景。在常规应用程序代码中,应谨慎进行转换。

不要在C ++中使用C风格的强制转换。 C ++有自己的强制转换系列,很容易在代码中搜索,并且通常会指定演员实际执行的更多内容。在这种特殊情况下,您可以使用const_cast,它可以准确显示您正在做什么并且很容易找到。

答案 7 :(得分:2)

因为C知道程序员总是知道他们在做什么,总是做正确的事情。你甚至可以把它像:

void* ptr2 = (int(*)(void(*)(char*), int[])) ptr1;
(*(int*)ptr2) = 3;

它甚至都不会抱怨。

答案 8 :(得分:1)

语句const int i = 2;表示符号/变量i包含值2无法使用i更改值;但不能保证价值不能通过其他方式改变(如OP的例子中所示)。