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

时间:2015-02-05 21:21:09

标签: c linker const header-files

例如,我可以执行以下操作,以便只有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\n", foo);
    foo_reinit(); printf("foo: %d\n", foo);
    return 0;
}

以下情况会产生错误/警告:

baz.c

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

这是否可以保证正确链接?

4 个答案:

答案 0 :(得分:5)

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

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

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

然后,您可以在实际允许更改它的模块中#undef foo

答案 1 :(得分:5)

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

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

  

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

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

  

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

答案 2 :(得分:2)

当你踏上冰块时,你喜欢它的厚度有多薄?

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

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

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

答案 3 :(得分:1)

不,你不能,但正如我理解你的代码,你可以将foo静态,作为函数foo_initfoo_reinit,并公开一个简单的{{1其他模块。