我应该#include 一个库 header 吗?
Should I #include a library header?
假设我只想要来自某个 header 的一个(或几个)函数,但它是一个我可以定义的函数,其效率与库的实现相同。我应该包含一个库 header 还是实现我自己的功能?哪个更好?
我正在学习我的第一门语言 C,我很喜欢它。
编辑:
你们中的大多数人没有得到问题。忘掉可移植性,如果它让你高兴“假设”我可以以完全相同的效率制作一个功能。或者假设我以某种方式获得了相同的实现。
我在某处读到
The #include directive tells the preprocessor to open a specified file and insert its contents into the current file.
像 这样的 header 由很多东西组成,所以我想知道是将它的所有内容插入到文件中,还是插入自定义的 header 我想要的内容,就速度或内存或程序大小而言,哪个更有效?
是的,使用已经编写的,并且可能经过更好测试的版本。
I can define with the same efficiency as the library's implementation
你误会了。我不在乎你是 Kernighan 还是 Ritchie 或其他人,你不会编写比编译器标准库优化一半的代码。您将遇到需要修复的错误,因此当出现崩溃时您将永远无法信任您的标准库,因此您也必须始终调试它。
欢迎来到 Stack Overflow。首先让我说你问的一般不会发生。通常创建库是为了防止 re-writing 大量代码。但是,如果真的发生了,首先要考虑的就是便携性。
虽然不完全准确,但我们可以假设部署的软件比您编写的程序更有可能得到维护。如果需要对该软件进行更改,您将在更新系统和 re-compiling.
后最终引入该更改
如果另一方面,如果您确定即使发生某些更改,您也不希望它发生更改,那么一定要自己实施。假设您的代码与库一样高效,则不会有性能差异。
我认为你在学习的过程中,应该按顺序做以下两件事:
- 实施并测试您的 home-grown 函数
- 查看库函数与您的实现有何不同
库函数并不总是“最佳”解决方案:它们通常是最好的,但不一定是最有效的。
尽管我在工作中几乎完全依赖于库,但像许多程序员一样,我开始使用许多 home-grown(和错误的)标准库函数的等价物。编写该代码帮助我成为了更好的程序员。
正在将所选评论(主要是我的)的编辑版本传输到答案中。
Include the header - the header author may change something in the header file that might cause all sorts of isssues for your code. pm100
注意 C 标准明确指出 (§7.1.4 Use of library functions ¶2):
Provided that a library function can be declared without reference to any type defined in a header, it is also permissible to declare the function and use it without including its associated header.
你想做的事情是允许的(有警告),但这样做是 ill-advised。使用 header.
您在担心 micro-optimizations。 不要! 除非您进行编译的计算机上的芯片速度以 double-digits 兆赫兹或更低为单位测量,否则您是在浪费时间来节省微不足道的金额计算机时间。
- 包含 headers. 包含标准 headers.
如果您在一个模块中达到 50 headers,那么您可能会开始担心。你还没到。如果 header 写得正确,你仍然不会击败他们。使用 header 可以保护您免受 header 中声明的更改。没有什么比发现 header 没有被包含但一些声明是手写的,然后函数在 header 中被更改更令人沮丧的了,但你不知道,因为你没有使用header。这是一场 double-maintenance 噩梦——如果您在多个文件中有旧版本的函数声明,那么这比 double-maintenance 噩梦更糟。
一般来说,header只声明函数和调用函数所需的支持信息(类型、宏)。该函数的实现在单独 linked 的库中。您使用 header 作为声明,这样您就可以调用函数——它们的实现在 link 和执行程序时加载的库中。您不会在代码中获得函数的副本 - 当您 link 程序时,有一个库提供该函数。因此,包含 <stdlib.h>
可以调用多种函数,但不会将它们添加到您的 object 文件中。
您不会重新实现库中的内容,除非它有缺陷。你用库,要用库,你用header。 header 包含函数的声明;该库包含函数的实现。如果它是标准 C 库代码,或者 POSIX 库代码,或者 O/S 额外函数,您将在运行时加载共享库。如果您使用静态 linking,函数将 linked 到您的可执行文件中。无论哪种方式,您都不必担心 - 学习时不会担心,通常以后也不会。
您正在担心micro-optimizations。你不应该担心 micro-optimizations 呢。好久不见了。
您似乎想要回答“不要包含 header 因为其中的所有垃圾会使您的程序变得比必要的更大”的效果。这不是正确的答案,因为包含 header 不会使您的程序变得比必要的更大。
- A header 仅包括声明 — 不包括定义。
- 声明不会在您的可执行文件中占用 space(尽管它们在编译器中占用一些 space)。
- 定义确实在您的可执行文件中使用 space。
如果您的系统在运行时使用共享库,整个共享库将在内存中。然而,所有使用同一个共享库的进程都将使用相同的内存来存储代码(但每个进程都有自己的任何可修改数据的副本),因此在内存上有一个净赢 space.
静态 linking 改变了 space 等式。 statically-linked 程序将包含它使用的函数,以及这些函数使用的函数,但不包含它不需要的任何内容。这将与任何其他程序使用的代码完全分开,因此如果您有多个 statically-linked 程序 运行,每个程序在内存中都有自己的映像,包括它自己的任何库函数副本。如果您有自己的任何函数的实现 linked 到您的程序中,这些将在每个程序中占用单独的内存,因为它们是静态 linked.
而且,如果您的程序使用任何共享库,它们仍会加载到系统中,因此您未使用的共享库中的函数会产生开销。
这不是便携性的问题;这不是替换函数的运行时效率的问题。这是一个理智和基本良好软件工程的问题。您不 re-create 编写代码是有充分理由的。
并且(关键点),包括 header 不会使您的程序增长。
(注意:C++ 确实有 'header-only' 带有模板的库——Boost 库是一个主要的例子。包括这样的 headers 意味着你的代码调用的函数可以使用信息实例化来自 header。linker 通常通过消除实例化函数的重复副本来设法避免过多的开销。因此,您仍然不必担心程序增长,因为包含 headers. Header-only 图书馆很少见C.)
假设我只想要来自某个 header 的一个(或几个)函数,但它是一个我可以定义的函数,其效率与库的实现相同。我应该包含一个库 header 还是实现我自己的功能?哪个更好?
我正在学习我的第一门语言 C,我很喜欢它。
编辑:
你们中的大多数人没有得到问题。忘掉可移植性,如果它让你高兴“假设”我可以以完全相同的效率制作一个功能。或者假设我以某种方式获得了相同的实现。
我在某处读到
The #include directive tells the preprocessor to open a specified file and insert its contents into the current file.
像
是的,使用已经编写的,并且可能经过更好测试的版本。
I can define with the same efficiency as the library's implementation
你误会了。我不在乎你是 Kernighan 还是 Ritchie 或其他人,你不会编写比编译器标准库优化一半的代码。您将遇到需要修复的错误,因此当出现崩溃时您将永远无法信任您的标准库,因此您也必须始终调试它。
欢迎来到 Stack Overflow。首先让我说你问的一般不会发生。通常创建库是为了防止 re-writing 大量代码。但是,如果真的发生了,首先要考虑的就是便携性。
虽然不完全准确,但我们可以假设部署的软件比您编写的程序更有可能得到维护。如果需要对该软件进行更改,您将在更新系统和 re-compiling.
后最终引入该更改如果另一方面,如果您确定即使发生某些更改,您也不希望它发生更改,那么一定要自己实施。假设您的代码与库一样高效,则不会有性能差异。
我认为你在学习的过程中,应该按顺序做以下两件事:
- 实施并测试您的 home-grown 函数
- 查看库函数与您的实现有何不同
库函数并不总是“最佳”解决方案:它们通常是最好的,但不一定是最有效的。
尽管我在工作中几乎完全依赖于库,但像许多程序员一样,我开始使用许多 home-grown(和错误的)标准库函数的等价物。编写该代码帮助我成为了更好的程序员。
正在将所选评论(主要是我的)的编辑版本传输到答案中。
Include the header - the header author may change something in the header file that might cause all sorts of isssues for your code. pm100
注意 C 标准明确指出 (§7.1.4 Use of library functions ¶2):
Provided that a library function can be declared without reference to any type defined in a header, it is also permissible to declare the function and use it without including its associated header.
你想做的事情是允许的(有警告),但这样做是 ill-advised。使用 header.
您在担心 micro-optimizations。 不要! 除非您进行编译的计算机上的芯片速度以 double-digits 兆赫兹或更低为单位测量,否则您是在浪费时间来节省微不足道的金额计算机时间。
- 包含 headers. 包含标准 headers.
如果您在一个模块中达到 50 headers,那么您可能会开始担心。你还没到。如果 header 写得正确,你仍然不会击败他们。使用 header 可以保护您免受 header 中声明的更改。没有什么比发现 header 没有被包含但一些声明是手写的,然后函数在 header 中被更改更令人沮丧的了,但你不知道,因为你没有使用header。这是一场 double-maintenance 噩梦——如果您在多个文件中有旧版本的函数声明,那么这比 double-maintenance 噩梦更糟。
一般来说,header只声明函数和调用函数所需的支持信息(类型、宏)。该函数的实现在单独 linked 的库中。您使用 header 作为声明,这样您就可以调用函数——它们的实现在 link 和执行程序时加载的库中。您不会在代码中获得函数的副本 - 当您 link 程序时,有一个库提供该函数。因此,包含 <stdlib.h>
可以调用多种函数,但不会将它们添加到您的 object 文件中。
您不会重新实现库中的内容,除非它有缺陷。你用库,要用库,你用header。 header 包含函数的声明;该库包含函数的实现。如果它是标准 C 库代码,或者 POSIX 库代码,或者 O/S 额外函数,您将在运行时加载共享库。如果您使用静态 linking,函数将 linked 到您的可执行文件中。无论哪种方式,您都不必担心 - 学习时不会担心,通常以后也不会。
您正在担心micro-optimizations。你不应该担心 micro-optimizations 呢。好久不见了。
您似乎想要回答“不要包含 header 因为其中的所有垃圾会使您的程序变得比必要的更大”的效果。这不是正确的答案,因为包含 header 不会使您的程序变得比必要的更大。
- A header 仅包括声明 — 不包括定义。
- 声明不会在您的可执行文件中占用 space(尽管它们在编译器中占用一些 space)。
- 定义确实在您的可执行文件中使用 space。
如果您的系统在运行时使用共享库,整个共享库将在内存中。然而,所有使用同一个共享库的进程都将使用相同的内存来存储代码(但每个进程都有自己的任何可修改数据的副本),因此在内存上有一个净赢 space.
静态 linking 改变了 space 等式。 statically-linked 程序将包含它使用的函数,以及这些函数使用的函数,但不包含它不需要的任何内容。这将与任何其他程序使用的代码完全分开,因此如果您有多个 statically-linked 程序 运行,每个程序在内存中都有自己的映像,包括它自己的任何库函数副本。如果您有自己的任何函数的实现 linked 到您的程序中,这些将在每个程序中占用单独的内存,因为它们是静态 linked.
而且,如果您的程序使用任何共享库,它们仍会加载到系统中,因此您未使用的共享库中的函数会产生开销。
这不是便携性的问题;这不是替换函数的运行时效率的问题。这是一个理智和基本良好软件工程的问题。您不 re-create 编写代码是有充分理由的。 并且(关键点),包括 header 不会使您的程序增长。
(注意:C++ 确实有 'header-only' 带有模板的库——Boost 库是一个主要的例子。包括这样的 headers 意味着你的代码调用的函数可以使用信息实例化来自 header。linker 通常通过消除实例化函数的重复副本来设法避免过多的开销。因此,您仍然不必担心程序增长,因为包含 headers. Header-only 图书馆很少见C.)