【问题标题】:returning const pointer to const int返回指向 const int 的 const 指针
【发布时间】:2020-04-28 03:14:53
【问题描述】:

在这段代码中:

const int* const fun(const int *const ptr)
{
    return ptr;
}

int main()
{
    int i=9;
    int *main_ptr;
    main_ptr = fun(&i);
    return 0;
}

编译器警告:

警告:赋值从指针目标类型中丢弃“const”限定符 [-Wdiscarded-qualifiers] main_ptr = fun(&i);

在将main_ptr 定义为指向const int 的指针时,警告会消失(这是可以理解的),但编译器不会抱怨在从const 指针降级为仅指针时丢弃const 限定符。

在一种情况下是警告行为而在另一种情况下没有警告,因为在这种情况下,当涉及到指向 const int 的指针时,当函数 fun 结束时,指向的变量不会被破坏,并且由于同样的原因 const 指向 int 部分的指针无关紧要,因为变量是本地的并且当 fun 结束时它会被破坏?

【问题讨论】:

  • "编译器不会抱怨丢弃 const 限定符,同时从指向 intconst 指针降级为指向 int 的指针。"我不明白你的意思。在编译器不发出警告的情况下会发生这种情况?
  • 您也谈到了const int,但您的代码中没有const int 类型的内容。
  • @jamesdlin 它的指针指向const int,当const 指针降级为仅指针时,编译器不会发出警告/错误。
  • @AgrudgeAmicus 函数参数是按值传递的,因此fun 没有机会修改main_ptr,因此没有可能的 const 违规警告。这与“被指向的变量没有被破坏”无关,我不确定在这种情况下什至意味着什么。
  • @AgrudgeAmicus 您引用的警告抱怨您将const T*(指向const 的指针)转换为T*。或者“const 指针”是指T* const?这与将const int 分配给int 没有什么不同。

标签: c pointers parameters constants


【解决方案1】:

限定符(constvolatilerestricted_Atomic)仅适用于左值(内存中对象的指示符),不适用于值(表达式中的数据)。每 C 2018 6.7.3 5:

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

考虑const int x = 3; int y = x;。这是允许的。 const 是对 x 的限制。一旦读取x 的值,结果就是int 3;没有const附加到3。那么我们可以将y的值设置为3,并且不要求y之后不改变。 const 不坚持这个值,编译器不会警告我们。

声明const int* const fun(const int *const ptr) 表示fun 返回的const。这是没有意义的,一个好的编译器可能会警告const 之前的fun 无效。无论如何,在评估函数调用时会丢弃此限定符,因此将此函数的返回值分配给不是const 的指针是没有问题的。

我们可以考虑一个更简单的例子:

int t;
const int * const x = &t;
const int *       y = x;

编译器不会对此发出警告,因为y 只接收x 的值。 x 可能不会改变这一事实并不妨碍我们将其值分配给 y 的能力,它可以改变。

补充

当一个左值用于表达式中的值时,它的所有限定符都被丢弃。 C 2018 6.3.2.1 2 说:

除非它是sizeof 运算符、一元& 运算符、++ 运算符、-- 运算符或. 运算符或赋值运算符的左操作数,没有数组类型的左值被转换为存储在指定对象中的值(并且不再是左值);这称为左值转换。如果左值具有限定类型,则该值具有左值类型的非限定版本; …

每个限定符都说明了如何处理内存中的对象

  • const 表示内存中的对象不会被修改(通过这个左值)。
  • volatile 表示内存中的对象可以通过 C 实现未知的方式更改,或者访问它会导致 C 编译器未知的影响。
  • restrict 表示内存中的对象只能通过从该特定左值派生的方式进行访问。
  • _Atomic 表示对内存中对象的访问表现得好像它是一个不可分割的东西(不是由可以单独读取或修改的字节组成),因此来自多个线程的访问总是使用它的“整体”值,从不混合来自不同线程的部分访问。

【讨论】:

    【解决方案2】:

    这里有两种类型的“不匹配”,第一种是

    main_ptr = fun(...)    // const int *const -> int *
    

    我们通过将fun 的返回值分配给main_ptr 来丢弃constness,第二个是

    ... = fun(&i)          // int * -> const int *const
    

    我们将一个普通的旧 int * 传递给一个接受 const int *const 的函数。

    正如您所注意到的,在执行第一个操作时您会收到警告,因为我们失去了 fun 的返回类型所做的安全保证。

    第二个不是问题,因为我们在执行fun 期间获得了安全保证,即参数指向一个常量整数。实际上,该参数并不引用常量int,但添加更多限制性const 限定符并没有什么坏处。移除它们存在危险,因此您会在第一种情况下收到警告。

    【讨论】:

    • 这个问题特别是关于为什么const int * const fun(const int *const ptr) 的第二个const 可能会被丢弃。本质上,它询问为什么int t; const int * const x = &t; const int * y = x; 不会产生错误。这个答案没有解决这个问题。
    • @EricPostpischil 感谢您的澄清。在我回答的时候,很难确定这个问题在问什么。另外,您从哪里提取 C 标准引号?是否有您知道的标准的可搜索副本?
    • 我购买了 2018 年标准的副本。有关官方和草稿版本的信息是here
    猜你喜欢
    • 1970-01-01
    • 2015-09-10
    • 1970-01-01
    • 2012-11-07
    • 1970-01-01
    • 2021-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多