为啥首先允许指针从非常量到常量的隐式转换?

Posted

技术标签:

【中文标题】为啥首先允许指针从非常量到常量的隐式转换?【英文标题】:Why is an implicit conversion from non-const to const allowed for pointers in the first place?为什么首先允许指针从非常量到常量的隐式转换? 【发布时间】:2016-08-24 13:32:22 【问题描述】:

我了解在处理值时从 non-constconst 的隐式转换并不危险,例如:

int mutable = 5;
const int immutable = mutable;

但是,在使用指针时,我可以执行以下操作:

int some_number = 5;
int *mutable = &some_number;
const int *immutable = mutable;    // <= Legal, but isn't it dangerous?

// Let's try to break const
printf("%d\n", *immutable);        // Prints 5
mutable[0] = 10;
printf("%d\n", *immutable);        // Prints 10

顺便说一句,对于双指针,这是不允许的(至少你会得到一个警告)!请参阅this 问题和其中的参考资料。

【问题讨论】:

常量指针的常见用例是作为函数参数。这告诉函数的用户(以及编译器)该函数不会改变指针指向的数据。 您的示例没有“破坏 const”,因为被修改的对象 (some_number) 不是 const。在指针目标上使用 const 并不意味着“如果你读了两次就保证产生相同的值,中间还会发生一些其他的事情” const 视为承诺。为什么有人要违背自己的诺言? 您的代码中没有const 限定指针! @Olaf:这不是重点,而是基础价值的变化 【参考方案1】:

来自the C11 standard (draft N1570):

6.7.3 类型限定符

语法

    类型限定符:constrestrictvolatile_Atomic

[...]

语义:

    与限定类型关联的属性仅对左值表达式有意义。

[...]

示例 1

声明的对象

extern const volatile int real_time_clock;

可由硬件修改,但不能分配、递增或递减。

简单来说:

const 并不意味着值永远不会改变。这只意味着不允许改变它1.

对于被调用者const 是一个限制,而不是一个承诺。 然而,对于调用者,它一个承诺。将const 指针传递给函数,您可以放心地假设该函数不会更改您的数据2,因此是“向您做出承诺”。


1 ...通过带有const限定符的标识符。2 ...通过传递给它的const参数。

【讨论】:

我忘了说我用的是C99,但我猜那里的标准是相似的。感谢您的澄清! 但奇怪的是,对于双指针,确实会发出警告,以防止我刚才对单指针所做的事情,请参阅c-faq.com/ansi/constmismatch.html "只表示不允许你修改。" - 甚至没有!我的意思是程序员保证不会修改它。 将 const 指针传递给函数,您可以放心地假设该函数不会更改您的数据,因此是“向您做出承诺” 这是不正确的,该函数仍可能通过全局值的其他参数更改数据。 这不是答案中写的。您的评论补充说:通过该论点,这是一个重要的区别。

以上是关于为啥首先允许指针从非常量到常量的隐式转换?的主要内容,如果未能解决你的问题,请参考以下文章

为啥允许从 int 到 byte 但不允许从 long 到 int 的隐式缩小转换?

为啥 Java 和 C# 没有到布尔值的隐式转换?

在构造 std::variant 时禁用从指针类型到 bool 的隐式转换的最佳方法是啥?

ARC 中不允许从 NSInteger 到 NSString 的隐式转换.. 应该使用啥解决方法来处理整数

不允许从数据类型 nvarchar 到 varbinary(max) 的隐式转换

不允许从数据类型 nvarchar 到 varbinary(max) 的隐式转换