【问题标题】:Passing structure to parameter of type `const struct` does not produce a warning将结构传递给“const struct”类型的参数不会产生警告
【发布时间】:2021-07-03 15:36:03
【问题描述】:

在以下示例中,非 const 限定指针 b 被传递给 func,它需要一个指向 const 限定类型的指针。因此,我希望编译器发出警告。但是,如果我用 clang 和 -Wall -Wextra -pedantic 编译这个程序,则没有警告。这是为什么呢?

#include <stdlib.h>
#include <string.h>
#define N 5


struct Bear {
    int n;
    int v;
    int *data;
};


void func (const struct Bear *bear, int *data, const size_t n)
{
    memcpy (bear->data, data, n);    
}


int main (void)
{
    int arr[N];
    int *mem = malloc (N*sizeof (int));
    if (mem == NULL) return -1;

    struct Bear *b = &(struct Bear){1, 2, mem};
    func (b, arr, N);

    free (mem);
    return 0;
}

此外,如果我将结构初始化的行更改为

const struct Bear *b = &(const struct Bear){1, 2, mem};

仍然没有警告。我知道结构声明中的const 应用于其字段,因此func 中的bear-&gt;v = 11; 显然是一个错误(并产生警告)。但是,对于指针来说,这似乎并不成立。

这是未定义的行为吗?我在这里错过了什么?

【问题讨论】:

  • 您可以将非常量传递给 const。当您尝试将 const 传递给非 const 时会出现警告,因为这表明可以修改指针目标。例如,strcpy 之类的东西采用 const char * 源参数,表明它没有被修改,但您可以传递任何 char * 作为该参数。
  • 在函数声明中将指针声明为指向 const 的指针只是告诉编译器(和使用该函数的程序员)该函数不会更改指针引用的对象。它不需要您传递指向 const 的指针。换句话说,从程序员的角度来看,在函数声明中使用 const 只不过是关于函数行为的文档。从编译器的角度来看,这是一个优化提示。
  • 请注意,memcpy (bear-&gt;data, data, n); 不会更改指针 bear-&gt;data,而只会更改它指向的内容。 memcpy 的原型保证了它,因为第一个操作符是带有 const 限定符的指针。

标签: c struct constants


【解决方案1】:

转换指针

根据 C 2018 6.5 调用具有原型的函数时,参数(bstruct Bear * 类型)将转换为相应参数的类型(bearconst struct Bear * 类型)。 2.2 7:

如果表示被调用函数的表达式具有包含原型的类型,则参数会隐式转换为相应参数的类型,就像通过赋值一样......

6.5.16.1 1 中的赋值约束包括允许转换为指向相同类型但添加了限定符(例如const)的指针:

…左操作数具有原子、限定或非限定指针类型,并且…两个操作数都是指向兼容类型的限定或非限定版本的指针,并且左指向的类型具有指向的类型的所有限定符右边……

此外,C 2018 6.3.2.3 中讨论了指针的转换,其中第 2 段说:

对于任何限定符q,指向非q 限定类型的指针可以转换为指向q 限定类型的指针类型的版本...

很简单,限定词是对事物使用的限制;他们说它是用于该事物的某些潜在用途的子集。 const 限定符表示该对象将仅用于读取其值,而不是修改其值。1 因此,将指针传递给可能 被修改为一个表明它不会修改它的函数。因此,编写 C 标准的规则来允许这样做。

const 应用于结构

我了解结构声明中的 const 应用于其字段...

如果结构是const,则结构成员dataconst,但该成员是一个指针。所以这只意味着指针const。这并不意味着它所指向的const

脚注

1const 限定符不是修改对象的完全障碍。如果在没有const 的情况下定义了一个对象,则添加了const 的指向它的指针可以转换(使用强制转换)回一个没有const 的指针,并用于修改该对象。

【讨论】:

    猜你喜欢
    • 2020-09-30
    • 2018-05-23
    • 1970-01-01
    • 2018-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-30
    • 1970-01-01
    相关资源
    最近更新 更多