常量正确性和不可变的分配对象

发布于 2024-09-28 08:56:12 字数 811 浏览 2 评论 0原文

在最近的讨论中(请参阅此答案的评论), R.. 建议永远不要为指向 const 类型的指针创建别名,因为您将无法在符合要求的 C 程序中轻松释放引用的对象(记住:free() 采用非 const 指针参数并且 C99 6.3.2.3 只允许从非限定到限定的转换)。

C 语言显然假定任何已分配对象都存在所有者,即某处必须有人存储指向该对象的非 const 指针,并且此人负责释放。

现在,考虑一个库分配和初始化不可从用户空间代码修改的对象,因此函数调用始终返回 const 限定的指针。

显然,库是对象的所有者,应该保留一个非 const 指针,这有点愚蠢,因为用户已经提供了一个完全有效的但 const 的副本每个库调用的指针。

要释放这样的对象,库必须放弃 const 限定符;据我所知,以下

void dealloc_foo(const struct foo *foo)
{
    free((void *)foo);
}

是有效的 C;仅当 foo 参数另外经过 restrict 限定时,它才会无效。

然而,抛弃 const 似乎有些黑客行为。

除了从库函数的所有返回值中删除 const 之外,还有其他方法吗?这会丢失有关对象可变性的任何信息?

During a recent discussion (see comments to this answer), R.. recommended to never create aliases for pointer-to-const types as you won't be able to deallocate the referenced objects easily in a conforming C program (remember: free() takes a non-const pointer argument and C99 6.3.2.3 only allows conversions from non-qualified to qualified).

The C language obviously assumes the existance of an owner for any allocated object, ie someone somewhere has to store a non-const pointer to the object, and this someone is responsible for deallocation.

Now, consider a library allocating and initializing objects which are non-modifyable from user-space code, so function calls always return const-qualified pointers.

Clearly, the library is the owner of the object and should retain a non-const pointer, which is somewhat silly as the user already supplies a perfectly valid, but const copy of the pointer on each library call.

To deallocate such an object, the library has to discard the const qualifier; as far as I can tell, the following

void dealloc_foo(const struct foo *foo)
{
    free((void *)foo);
}

is valid C; it would only be invalid if the foo parameter were additionally restrict-qualified.

However, casting away const seems somewhat hack-ish.

Is there another way aside from dropping the const from all return values of library functions, which would lose any information about object mutability?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

愛上了 2024-10-05 08:56:12

我在 6.3.2.3 中没有读到同样的内容。该段落是关于隐式发生且不需要强制转换的转换。因此,可能不允许从指针到 const 对象的隐式转换,但这并没有说明显式强制转换。

6.5.4 中处理了强制转换,我没有看到任何会限制您对本身不符合 const 资格的任何指向 const 的指针进行强制转换的情况与(void*)。相反,它说

涉及指针的转换,
除经国家许可的情况外
的约束条件
6.5.16.1,应通过显式强制转换来指定。

所以我在那里读到,如果你明确地做某事,它们是被允许的。

所以我认为以下内容是完全有效的

char const *p = malloc(1);
free((void*)p);


What 6.5.4 forbits would be the following

char *const p = malloc(1);
free((void*)p); /* expression of cast is const qualified */


作为旁注,对于您的第二条想法,一个库返回一个指向 const 限定对象的指针,然后将其置于来电者,对我来说没有多大意义。库

  • 返回一个指向
    内部对象,那么它应该
    限定它指向const的指针以具有一些弱
    调用者没有的保护
    更改它,或者
  • 库返回一个新的
    分配的对象落在
    调用者的责任。然后它
    不应该太关心是否
    调用者更改它,因此它可能会返回
    指向非限定对象的指针。如果来电者
    然后想要确保
    内容并非偶然
    被覆盖或者他可能会做的事情
    将其分配给 const 指针,例如
    他的用途。

I don't read the same thing in 6.3.2.3. That paragraph is about conversions that happen implicitly and that don't need a casts. So an implicit conversion from a pointer-to-const object may be not permitted, but this says nothing about explicit casts.

Casts are handled in 6.5.4, and I don't see anything that would constrain you from a cast of any pointer-to-const that is by itself not const qualified with (void*). In the contrary it says

Conversions that involve pointers,
other than where permitted by the
constraints of
6.5.16.1, shall be specified by means of an explicit cast.

So I read there that if you do things explicitly, they are permitted.

So I think the following is completely valid

char const *p = malloc(1);
free((void*)p);


What 6.5.4 forbits would be the following

char *const p = malloc(1);
free((void*)p); /* expression of cast is const qualified */


As a side note, for your second line of thoughts, a library that returns a pointer-to-const qualified object that then is to be placed in the responsibility of the caller, makes not much sense to me. Either

  • the library returns a pointer to an
    internal object, then it should
    qualify it pointer-to-const to have some weak
    protection that the caller doesn't
    change it, or
  • the library returns a freshly
    allocated object that falls in the
    responsibility of the caller. Then it
    shouldn't care much of whether the
    caller changes it, so it may return
    a pointer-to-unqualified object. If the caller
    then wants to ensure that the
    contents is not accidentally
    overwritten or something he might
    assign it to a const pointer, for
    his use.
掩耳倾听 2024-10-05 08:56:12

如果您返回 const 限定的指针,则语义是不允许函数的调用者以任何方式修改该对象。这包括释放它,或将其传递给库中的任何函数来释放它。是的,我知道您可以放弃 const 限定符,但是这样您就违反了 const 所暗示的契约。

If you return a const-qualified pointer, the semantics are that the caller of your function is not permitted to modify the object in any way. That includes freeing it, or passing it to any function in your library that would in turn free it. Yes I'm aware that you could cast away the const qualifier, but then you're breaking the contract that const implies.

小梨窩很甜 2024-10-05 08:56:12

如果对象确实是不可变的,为什么要给用户提供指向它的指针并冒损坏对象的风险?将对象地址保留在表中,将不透明句柄(整数表索引?)返回给用户并在库例程中接受该句柄。

If the object is truly immutable, why give the user the pointer to it and risk an opportunity of corrupt object? Keep the object address in the table, return an opaque handle (an integer table index?) to the user and accept that handle in your library routines.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文