C / C ++:头文件中的静态函数是什么意思?

我知道什么时候在源文件中声明。 我读了一些代码,发现头文件中的静态函数可能会在其他文件中调用。

头文件中定义了函数吗? 所以实际的代码直接在函数中给出,如下所示:

static int addTwo(int x) { return x + 2; } 

那么这只是为许多不同的C文件提供有用的function的一种方式。 每个包含头文件的C文件都会得到自己的定义,可以调用它。 这当然会浪费内存,并且(在我看来)这是一个相当丑陋的事情,因为在头文件中使用可执行代码通常不是一个好主意。

请记住, #include :头文件基本上只是将头文件(和其包含的任何其他头文件)的内容粘贴到C文件中,如编译器所见。 编译器从来不知道一个特定的函数定义来自头文件。

更新 :在很多情况下,做上述事情实际上是一个好主意,我意识到我的回答听起来非常黑白,这有点过分简单化了。 例如,模型(或只是使用) 内部函数的代码可以像上面那样expression,甚至可以使用明确的inline关键字:

 static inline int addTwo(int *x) { __add_two_superquickly(x); } 

在这里, __add_two_superquickly()函数是一个虚构的内在的,因为我们希望整个函数基本上编译成一个单一的指令,我们真的希望它内联。 尽pipe如此,上面比使用macros更加清晰。

相对于直接使用内在的优势,当然是将其包装在另一个抽象层中,这使得可以在缺乏该特定内在的编译器上构build代码,通过提供替代实现并根据正在使用的编译器select正确的代码。

它将有效地创build一个单独的静态函数,在每个包含在其中的cpp文件中具有相同的名称。 这同样适用于全局variables。

正如其他人所说的,它与.c文件本身的static函数的含义完全相同。 这是因为.c.h文件之间没有语义上的区别。 只有编译单元由实际传递给编译器的文件(通常名为.c )组成,其中任何和所有以#include行(通常名为.h )命名的文件的内容都被插入stream中预处理器。

C源文件名为.c和公共声明的文件名是.h这只是一个约定。 但它通常是一个好的。 根据该惯例,应该在.h文件中出现的唯一情况是声明,因此通常避免在单个程序中多次定义相同的符号。

在这种特殊情况下, static关键字使符号对模块是私有的,所以没有多重定义冲突等待造成麻烦。 所以从这个意义上说,这样做是安全的。 但是如果没有保证函数会被内联,那么就会冒这个风险,就是在每个发生#include这个头文件的模块中都会实例化这个函数,而这个头文件最好是代码段中的内存浪费。

我不确定在通常可用的公共头文件中,什么用例可以certificate这一点。

如果.h文件是生成的代码,只包含在一个.c文件中,那么我会亲自命名该文件而不是.h以强调它实际上并不是公共头文件。 例如,将二进制文件转换为初始化variables定义的实用程序可能会编写一个打算通过#include使用的文件,并且很可能包含该variables的static声明,甚至可能包含访问者或其他相关的static定义效用函数。

在源文件或头文件中定义没有语义上的区别,在使用static关键字的时候,在plain C中基本都是一样的,这就限制了范围。

但是,在头文件中写入这个问题是有问题的,这是因为每次将头文件包含在源文件中时,您都会得到一个具有相同实现的函数副本,这与在头文件中定义的正常函数非常相似文件。 通过在头文件中添加定义,你不能达到静态函数的目的。

因此,我build议你应该只在你的源文件中实现你的实现,而不是在头文件中。

在一些带有小内联函数的“仅标题”库中是有用的。 在这种情况下,你总是想做一个函数的副本,所以这不是一个坏的模式。 但是,这给你一个简单的方法来在单个头文件中插入单独的接口和实现部分:

 // header.h // interface part (for user?!) static inline float av(float a, float b); // implementation part (for developer) static inline float av(float a, float b) { return (a+b)/2.f; } 

GLK框架中的Applevectormath库使用了这样的构造(例如GLKMatrix4.h)。

如果你在头文件中定义函数(不是简单地声明它),函数的副本将在每个翻译单元(基本上在包含这个头文件的每个cpp文件中)中生成。

这可能会增加可执行文件的大小,但是如果函数很小,这可能可以忽略不计。 优点是大多数编译器可以内联函数,这可能会增加代码的性能。

但是这样做可能会有很大的差别,这在任何答案中都没有提到。 如果你的函数使用一个静态局部variables如:

 static int counter() { static int ctr = 0; return ctr++; } 

而不是:

 //header int counter(); //source int counter() { static int ctr = 0; return ctr++; } 

然后每个包含这个头文件的源文件都有自己的计数器。 如果函数是在头文件中声明的,并在源文件中定义,那么计数器将在整个程序中共享。

所以说唯一的区别是性能和代码大小是错误的。