5

我有一个 C 项目,其中所有代码都组织在*.c/*.h文件对中,我需要在一个文件中定义一个常量值,但是它也将用于其他文件。我应该如何声明和定义这个值?

应该static const ...*.h文件里的一样吗?如extern const ...*.h文件中并在文件中定义*.c?如果值不是原始数据类型(int,double等),而是 achar *或 a ,这有什么关系struct?(虽然在我的情况下它是一个double。)

通常,在文件中定义东西*.h似乎不是一个好主意。应该在文件中声明事物*.h,但在文件中定义它们*.c。但是,这种extern const ...方法似乎效率低下,因为编译器无法内联该值,而是必须始终通过其地址访问它。

我想这个问题的本质是:是否应该在 Cstatic const ...中的文件中定义值*.h,以便在多个地方使用它们?

4

9 回答 9

8

我遵循的规则是只在 H 文件中声明事物并在 C 文件中定义它们。您可以在单个 C 文件中声明和定义,假设它只会在该文件中使用。

通过声明,我的意思是通知编译器它的存在,但不为其分配空间。这包括#definetypedefextern int x等。

定义为声明分配值并为它们分配空间,例如int xconst int x。这包括函数定义;将这些包含在头文件中经常会导致代码空间的浪费。

我见过太多初级程序员const int x = 7;在输入头文件时感到困惑,然后想知道为什么他们会因为x多次定义而出现链接错误。我认为至少,您需要static const int x避免这个问题。

我不会太担心代码的速度。很久以前,计算机的主要问题(在速度和成本方面)从执行速度转移到易于开发。

于 2008-12-10T06:46:18.853 回答
3

如果您需要常量(真实的,编译时常量),您可以通过三种方式进行操作,将它们放入头文件中(这没什么不好):

enum {
    FOO_SIZE = 1234,
    BAR_SIZE = 5678
};

#define FOO_SIZE 1234
#define BAR_SIZE 5678

static const int FOO_SIZE = 1234;
static const int BAR_SIZE = 5678;

在 C++ 中,我倾向于使用枚举方式,因为它可以限定在命名空间中。对于 C,我使用宏。不过,这基本上归结为品味问题。如果需要浮点常量,就不能再使用枚举了。在 C++ 中,我使用最后一种方式,即 static const double,在这种情况下(注意在 C++ 中静态将是多余的;它们会自动变为静态,因为它们是 const)。在 C 中,我会继续使用宏。

使用第三种方法会以任何方式减慢您的程序,这是一个神话。我只是更喜欢枚举,因为你得到的值是右值——你不能得到它们的地址,我认为这是一个额外的安全。此外,编写的样板代码要少得多。眼睛集中在常数上。

于 2008-12-10T23:14:50.980 回答
1

你真的需要担心内联的优势吗?除非您正在编写嵌入式代码,否则请坚持可读性。如果它真的是一个神奇的数字,我会使用定义;我认为 const 更适合 const 版本字符串和修改函数调用参数。也就是说,.c 中的定义,.h 中的声明规则绝对是一个相当普遍接受的约定,我不会仅仅因为您可能会节省内存查找而破坏它。

于 2008-12-10T07:28:10.953 回答
1

作为一般规则,您不会像static在标题中那样定义事物。如果您确实在标头中定义static变量,则使用标头的每个文件都会获得其自己声明的任何内容的私有副本static,这与DRY原则相反:不要重复自己

因此,您应该使用替代方案。对于整数类型,使用 enum(在头文件中定义)非常强大;它也适用于调试器(尽管更好的调试器也可以帮助处理#define宏值)。对于非整数类型,头文件中的extern声明(可选地用 限定const)和一个 C 文件中的单个定义通常是最好的方法。

于 2008-12-10T07:53:24.617 回答
0

我可以给你一个间接的答案。在 C++(与 C 相对)中const意味着static. 也就是说,在 C++static const中与const. 这样就可以告诉您 C++ 标准机构对这个问题的看法,即所有consts 都应该是静态的。

于 2008-12-10T06:26:14.823 回答
0

我想为您的问题查看更多背景信息。值的类型很关键,但您忽略了它。C 中 const 关键字的含义相当微妙;例如 const char *p; 并不意味着指针 p 是一个常数;你可以随心所欲地写p。你不能写的是 p 指向的内存,即使 p 的值发生变化,这仍然是正确的。这是我真正理解的唯一案例;一般来说,我不知道 const 的微妙位置的含义。但是这种特殊情况对于函数参数非常有用,因为它从函数中提取参数指向的内存不会被改变的承诺。

每个人都应该知道另一种特殊情况:整数。几乎总是,常量,命名整数应该在 .h 文件中定义为枚举文字。枚举类型不仅允许您以自然的方式将相关常量组合在一起,而且还允许您在调试器中看到这些常量的名称,这是一个巨大的优势。

我写了几万行C;如果我试图追踪它,可能有数百个。(wc ~/src/c/*.c 说 85000,但其中一些是生成的,当然还有很多 C 代码潜伏在其他地方)。除了这两种情况之外,我从来没有发现 const 有什么用处。我很高兴学习一个新的有用的例子。

于 2008-12-10T06:29:07.483 回答
0

对于 autoconf 环境:您也可以始终在配置文件中定义常量。AC_DEFINE() 我猜是在整个构建中定义的宏。

于 2008-12-10T08:26:59.807 回答
0

要回答您问题的本质:
您通常不想在头文件中定义静态变量。
这将导致您在包含标题的每个翻译单元(C 文件)中都有重复的变量。

标头中的变量实际上应该声明为 extern,因为这是隐含的可见性。请参阅此问题以获得很好的解释。

实际上,情况可能并不那么可怕,因为编译器可能会将 const 类型转换为文字值。但是您可能不想依赖这种行为,尤其是在关闭优化的情况下。

于 2008-12-10T12:36:36.977 回答
0

在 C++ 中,您应该始终使用

const int SOME_CONST = 17;

对于常量,从不

#define SOME_CONST 17

定义几乎总是会在以后回来咬你。常量在语言中,并且是强类型的,所以你不会因为一些隐藏的交互而得到奇怪的错误。我会将 const 放在适当的头文件中。只要它是#pragma once(或#ifndef x / #define x / #endif),你就不会得到任何编译错误。

在 vanilla C 中,您可能会遇到必须使用#defines 的兼容性问题。

于 2008-12-11T00:40:16.080 回答