0
点赞
收藏
分享

微信扫一扫

指向数组的指针与指向const数组的指针不兼容?(pointer to array not compatible to a pointer to 'const' array?)...


  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;

  }

  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

  #include

  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;

  }

  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;

  ~^~~~~~~~

  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:

  Is my assumption correct that this doesn't lead to a hole in const correctness?

  Does the explicit cast violate the standard here?

  盾畳圭宛

  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.

  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;

  Now you can return a const shape_t* just fine.

  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) 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

  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.

  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

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

  and C11 6.7.3/10

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

  of a compatible type

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

举报

相关推荐

指向函数的指针

0 条评论