我可以在公共标头中而不是在私有标头中将变量声明为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 int
和int
是两种类型不兼容的类型。
(C11,6.7.3p10)“对于两个要兼容的限定类型,两者都应具有相同类型的兼容类型;说明符或限定符列表中类型限定符的顺序不会影响指定的类型”
不可以。如果声明不匹配,程序的行为是不确定的。特别是,由于使用公共头的翻译单元声明该对象是const
限定的,因此编译器在翻译它们时可以假设指向的数据永远不会改变,因此它可以在调用之前缓存值。外部函数,包括改变它的函数。
如果您只是想要防止意外编写试图修改数据的代码,请执行以下操作:
extern int foo;
#define foo (*(const int *)&foo)
然后你可以在实际允许更改它的模块中使用#undef foo
。
当你踩到它时,你喜欢你的冰有多薄?
是的,你可以做到。你会有点侥幸逃脱。但该标准并不保证您的代码能够按预期工作。应该在任何地方一致地声明相同的对象。
但主要的麻烦是你丢失了你应该要求的交叉检查,因为你的“私有”代码应该使用公共头来确保外部使用的声明与实现相匹配。也就是说,foo.c
应该有#include "foo.h"
以确保消费者被告知使用的内容与实现提供的内容相匹配(在foo.c
中)。当你不这样做时,迟早会出现问题。
另外,请记住,编译器讨厌被骗。当你骗他们时,他们会想办法让自己回来。你的代码对编译器说谎。
不,你不能,但正如我理解你的代码,你可以让foo
静态,作为函数foo_init
和foo_reinit
,并将一个简单的get_foo
暴露给其他模块。
以上是关于我可以在公共标头中而不是在私有标头中将变量声明为const吗?的主要内容,如果未能解决你的问题,请参考以下文章
如何在所有请求中传输动态auth值,而不是在SOAPUI中更改每个请求的标头中的值
在 UITableView 标头中将标签约束设置为 0 时自动布局失败