指向数组的指针与指向"const"数组的指针不兼容? [英] pointer to array not compatible to a pointer to 'const' array?

查看:129
本文介绍了指向数组的指针与指向"const"数组的指针不兼容?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在C模块(也称为编译单元)中,我想要一些私有数据,但将其只读公开给外界.我可以通过在.c文件中声明的struct中有一个字段以及在.h文件中声明的函数来将指向const 的指针返回到该字段来实现这一点.例如,对于 string ,这可能类似于以下内容:

In a C module (aka, compilation unit), I want to have some private data, but expose it read-only to the outside world. I achieve that by having a field in a struct declared in my .c file and a function declared in my .h file that returns a pointer to const to that field. For example, this could look like the following for a string:

// header:

typdef struct foo foo;

const char *foostr(const foo *f);

// implementation:

struct foo
{
    char *str;
};

const char *foostr(const foo *f)
{
    return foo->str;
}

现在我的问题是,我有一个对象数组,这些对象本身就是数组.因此,在我的struct中,我有一个指向数组的指针,然后从函数中尝试返回一个指向相应的const数组的指针.考虑以下示例代码:

Now my problem is, I have an array of objects that are themselves arrays. So in my struct, I have a pointer to an array, and from my function, I try to return a pointer to the corresponding const array. Consider the following example code:

#include <stdlib.h>
#include <stdint.h>

typedef uint8_t shape[64];

typedef struct foo
{
    shape *shapes;
} foo;


foo *createfoo(void)
{
    foo *f = malloc(sizeof *f);
    if (!f) return 0;

    // 10 empty shapes:
    f->shapes = calloc(10, sizeof *(f->shapes));

    if (!f->shapes)
    {
        free(f);
        return 0;
    }

    return f;
}

const shape *fooshapes(const foo *f)
{
    return f->shapes;
}

使用gcc -c -std=c11 -Wall -Wextra -pedantic对此进行编译,会收到以下警告:

Compiling this with gcc -c -std=c11 -Wall -Wextra -pedantic, I get the following warning:

constarr.c: In function ‘fooshapes’:
constarr.c:31:13: warning: pointers to arrays with different qualifiers are incompatible in ISO C [-Wpedantic]
     return f->shapes;
            ~^~~~~~~~

我了解双指针指向const的双指针不兼容,还有其原因,但我认为这并不相关,还是?那么,为什么不允许它隐式地将指向数组的指针转换为指向const数组的指针呢?还有什么想法我应该怎么做?

I understand a double pointer isn't compatible to a double pointer to const, and also the reason for it, but I don't think this is related, or is it? So, why isn't it allowed to implicitly convert a pointer to an array to a pointer to a const array? And any ideas what I should do instead?

我现在要做的是添加一个像这样的显式演员表:

What I did now is adding an explicit cast like this:

const shape *fooshapes(const foo *f)
{
    return (const shape *) f->shapes;
}

这当然会使编译器安静下来,我几乎可以肯定它在实践中将始终正常运行.在这种情况下,常量孔"将不存在,因为对于数组,没有非常量内部指针.但这仍然给我提出了两个问题:

This of course silences the compiler and I am almost sure it will always work correctly in practice. The "const hole" can't exist in this case, as with an array, there is no non-const inner pointer. But it still leaves me with two further questions:

  • 我的假设是否正确,认为这不会导致const正确性方面的漏洞?
  • 显式强制转换是否违反了这里的标准?
  • Is my assumption correct that this doesn't lead to a hole in const correctness?
  • Does the explicit cast violate the standard here?

推荐答案

问题是,通过typedef:定义一个数组,然后const限定该类型的指针,您实际上得到了const uint8_t(*)[64],即与uint8_t(*)[64] 1)不兼容. const正确性和数组指针的行为笨拙,请参阅以获取同一问题的示例

The issue is that by typedef:ing an array and then const-qualifying a pointer to that type, you actually get an const uint8_t(*)[64], which is not compatible with uint8_t(*)[64] 1). Const correctness and array pointers behave awkwardly together, see this for an example of the same issue.

无论如何,在这种情况下,问题的根源在于将数组隐藏在typedef后面.这通常不是一个好主意.您可以通过将数组包装在结构中来解决此问题,这也可能总体上提供更好的设计.示例:

Anyway, the root of the problem in this specific case is hiding an array behind a typedef. This is usually not a good idea. You can fix this by wrapping the array inside a struct instead, which might also give a better design overall. Example:

typedef struct shape
{
  uint8_t shape[64];
} shape_t;

typedef struct foo
{
  shape_t shapes;
} foo_t;

现在您可以返回const shape_t*了.

您现在可以选择将shape_t设置为不透明类型,就像foo_t一样.或者,您也可以公开shape_t的内部结构,例如,将结构声明以公开的标头形状公开.h.

Optionally you can now either make shape_t an opaque type just like foo_t. Or you can make the internals of shape_t public by for example exposing the struct declaration in a public header shape.h.

1)唯一的允许的隐式转换是在指针类型和合格指针类型之间的隐式转换.

1) Implicit conversion between a pointer-to-type and a qualified-pointer-to-type is the only allowed implicit conversion.

C11 6.3.2.3/2

C11 6.3.2.3/2

对于任何限定词q,指向非q限定类型的指针都可以转换为指向 类型的q限定版本;存储在原始指针和转换后的指针中的值 应该比较相等.

For any qualifier q, a pointer to a non-q-qualified type may be converted to a pointer to the q-qualified version of the type; the values stored in the original and converted pointers shall compare equal.

这不适用于这里.为了使转换正常,它必须是从指针到数组类型到指针到合格数组类型的转换.

This does not apply here. For the conversion to be ok, it would have to be a conversion from pointer-to-array-type to pointer-to-qualified-array-type.

但是不是,它是从指针到数组类型到合格指针到数组类型的转换.

But it is not, it is a conversion from pointer to-array-type to qualified-pointer-to-array-type.

C中兼容类型的规范性文本是第6.2.7章,仅进一步引用6.7.3.相关部分:

Normative text for compatible types in C is chapter 6.2.7, which only references further to 6.7.3. Relevant parts:

C11 6.7.3/9

C11 6.7.3/9

如果数组类型的规范包括任何类型限定符,则元素类型是合格的,而不是数组类型.

If the specification of an array type includes any type qualifiers, the element type is so-qualified, not the array type.

和C11 6.7.3/10

and C11 6.7.3/10

要使两个合格的类型兼容,两者应具有相同的合格版本 兼容类型

For two qualified types to be compatible, both shall have the identically qualified version of a compatible type

这就是为什么gcc正确发出诊断消息的原因-指针不是完全相同的版本.

This is why gcc correctly issues a diagnostic message - the pointers are not identically qualified versions.

这篇关于指向数组的指针与指向"const"数组的指针不兼容?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆