我可以在公共标头中而不是在私有标头中将变量声明为const吗?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我可以在公共标头中而不是在私有标头中将变量声明为const吗?相关的知识,希望对你有一定的参考价值。

例如,我可以做这样的事情,只有foo.c可以修改变量foo?:

foo.h

extern const int foo;
void foo_init(void);
void foo_reinit(void);

foo.private.h

int foo;
void foo_init(void);
void foo_reinit(void);

foo.c

#include "foo.private.h"
void foo_init() { foo = 1; /* ... */ }
void foo_reinit() { foo++; /* ... */ }

bar.c

#include <foo.h>
int main()
{
    foo_init(); printf("foo: %d
", foo);
    foo_reinit(); printf("foo: %d
", foo);
    return 0;
}

因此,以下将产生错误/警告:

baz.c

#include <foo.h>
int main()
{
    foo_init(); printf("foo: %d
", foo);
    foo = 0; /* ERROR/WARNING for modifying const variable */
    return 0;
}

这保证正确链接吗?

答案

我可以在公共标头中而不是在私有标头中将变量声明为const吗?

不,你不能因为它调用未定义的行为。

(C11,6.2.7p2)“所有引用相同对象或函数的声明都应具有兼容类型;否则,行为未定义。”

const intint是两种类型不兼容的类型。

(C11,6.7.3p10)“对于两个要兼容的限定类型,两者都应具有相同类型的兼容类型;说明符或限定符列表中类型限定符的顺序不会影响指定的类型”

另一答案

不可以。如果声明不匹配,程序的行为是不确定的。特别是,由于使用公共头的翻译单元声明该对象是const限定的,因此编译器在翻译它们时可以假设指向的数据永远不会改变,因此它可以在调用之前缓存值。外部函数,包括改变它的函数。

如果您只是想要防止意外编写试图修改数据的代码,请执行以下操作:

extern int foo;
#define foo (*(const int *)&foo)

然后你可以在实际允许更改它的模块中使用#undef foo

另一答案

当你踩到它时,你喜欢你的冰有多薄?

是的,你可以做到。你会有点侥幸逃脱。但该标准并不保证您的代码能够按预期工作。应该在任何地方一致地声明相同的对象。

但主要的麻烦是你丢失了你应该要求的交叉检查,因为你的“私有”代码应该使用公共头来确保外部使用的声明与实现相匹配。也就是说,foo.c应该有#include "foo.h"以确保消费者被告知使用的内容与实现提供的内容相匹配(在foo.c中)。当你不这样做时,迟早会出现问题。

另外,请记住,编译器讨厌被骗。当你骗他们时,他们会想办法让自己回来。你的代码对编译器说谎。

另一答案

不,你不能,但正如我理解你的代码,你可以让foo静态,作为函数foo_initfoo_reinit,并将一个简单的get_foo暴露给其他模块。

以上是关于我可以在公共标头中而不是在私有标头中将变量声明为const吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何在所有请求中传输动态auth值,而不是在SOAPUI中更改每个请求的标头中的值

打包静态库时如何隐藏标题?

在 UITableView 标头中将标签约束设置为 0 时自动布局失败

JavaScript,在公共方法中将私有函数作为字符串调用,而不使用 eval(显示模式)

在集合中的整个请求中将 Postman 标头值保存到变量中

是否可以在 URL 本身中传递 HTTP 标头?