如何确定函数来自哪个头文件?

Posted

技术标签:

【中文标题】如何确定函数来自哪个头文件?【英文标题】:How to determine which include header file a function comes from? 【发布时间】:2014-01-11 15:21:54 【问题描述】:

在学习新功能时,我喜欢在调用它们时包含全名(例如,std::cin 而不是 cin)。是否有类似的方法来包含函数来自的标头?例如,有没有办法指定排序函数来自 <algorithm> 标头,而不是 <iomanip> 标头或其他?

例如,如果我可以使用类似std::algorithm::sort 而不是std::sort 来调用sort,那就太棒了。标准库中内置了如此多的标头,仅使用 std::* 实际上并不能提供那么多信息,并且很少具体告诉我 * 的来源。

显然,随着我对 C++ 的掌握越来越好,这可能没有必要,但我的目标是了解哪些函数与哪些标头一起使用,以便更好地学习标准库。

如果没有这种方法来指定函数,是否有一个函数可以用来确定哪个标头提供了该函数?

最终,我认为列出您将使用的与每个标题相关联的函数将是一种很好的编码习惯:

#include <iostream>  //std::cout, std::cin

这样人们就可以弄清楚什么来自哪里!考虑到 c++ 社区对名称清晰的令人钦佩的痴迷,为什么没有做更多的事情?

注意:这个问题是唯一可能的,因为 C++ 是一种非常非 Pythonic 的语言。毕竟“显式胜于隐式”。 :)

【问题讨论】:

不,这根本不是一个有用的功能。命名空间已经服务于......好吧,提供命名空间。文件和/或标头通常只是一个可以更改的实现细节(尽管不适用于标准库)。 Kerrek:我的观点是,标准命名空间非常庞大,并且有很多可能的头文件,因此在代码可读性方面,简单地使用 std::* 并不是特别有用。我见过包含 30 个头文件的代码,其中许多来自标准库,但不知道从哪里来。我知道 std::* 不是为了可读性,而是为了避免名称冲突,但为什么 将其设置为 11 并使其完全透明您的名称来自哪里?跨度> @neuronet 不要以具有 30 个标头的代码开头。它可能是压倒性的,它不必是那样的。从基础开始,使用简单的代码,逐步向上。 这正是你在 Java 中可以做到的,但在 c++ 中却不行 :) 但是,我认为你必须搜索一个 IDE,它可以帮助你了解每个函数的来源, 多年后我仍然很高兴我问了这个问题,至少可以帮助我了解为什么 Python 相比之下如此干净和漂亮。 :) PS 我现在是一名 Python 开发人员。 【参考方案1】:

例如,有没有办法指定排序函数来自&lt;algorithm&gt; 标头,而不是&lt;iomanip&gt; 标头或其他?

没有。 C++ 作为一种编译语言(故意忽略预处理器)不知道头文件的文件名,因此它们与头文件中定义的对象和类型的名称无关。

如果有帮助,there is no std::sort in &lt;iomanip&gt;

这也是一件很奇怪的事情。通过匹配参数类型来执行重载解析,这足以消除歧义。

例如,如果我可以使用类似std::algorithm::sort 而不是std::sort 来调用sort,那就太棒了。标准库中内置了如此多的标头,因此仅使用 std::* 实际上并不能提供那么多信息,并且很少具体告诉我 * 的来源。

没关系。你不需要知道它来自哪里。编译器不需要知道它来自哪里。这与实际使用 std::sort 完全无关。

C++ 标准库确实没有将其内容组织到许多子命名空间中,而是在大多数情况下坚持使用***::std。可以说,这使得使用标准库进行编码变得更加神秘,但实际上并非如此:它只会使查找规则复杂化,并且在处理运算符重载、模板实例化和friends.

最终,我认为列出您将使用的与每个标题相关联的函数将是一种很好的编码习惯:

#include <iostream>  //std::cout, std::cin

这样人们就可以弄清楚什么来自哪里!考虑到 c++ 社区对名称清晰的令人钦佩的痴迷,为什么没有做更多的事情?

虽然我对一些 POSIX/Linux 套接字头文件执行此操作,以便知道我将来可能删除哪些头文件,但我不会对标准头文件执行此操作。 C++ 社区知道std::cout 是在哪里声明的,如果他们忘记了,他们可以简单地查找它。

【讨论】:

"你不需要知道它来自哪里。编译器不需要知道它来自哪里。"这两句话不一样。我有时确实需要知道。例如,当我编写自己的 .h 文件并希望包含最少数量的标头时(例如,不在我的标头中使用“使用命名空间标准”)。虽然很清楚,这在 c++ 中以任何自然方式都无法实现,但这并不意味着它对人类用户没有用(与编译器不同)。 @neuronet:如果你认为你需要知道,那你就错了。让编译器成为您的代理。与之抗争,你就会失败。 所以如果有人因为编译器抛出'error: std::cin' has not been declared而需要在函数中包含相关的头文件(例如iostream),那么想知道哪个头文件是错误的他们忽略包含的文件?那是编程错误? @neuronet:这是一个截然相反的例子。知道某个符号 不是 的来源当然很重要,为此您拥有文档(各种在线参考资料、标准、您的书)。这与包含标头后知道符号的来源不同! 当然,您可以到互联网上查找所需的信息,但我的观点是,如果有一种简单的方式以编程方式访问它会很有帮助,或者甚至在函数名中包含路径。这两个例子只是说明了同一点,我的第二个例子更清楚,所以你必须同意我的观点。 :)【参考方案2】:

我从未听说有人想要这样的东西。

您可以做的一件事(这很乏味,因此在我看来不值得)是自己创建命名空间并在该命名空间中为您想要的每个名称使用using declarations

#include <iostream>

namespace iostream 
    using std::cout;
    using std::endl;


int main() 
    iostream::cout << 24 << iostream::endl;
    return 0;

我的建议是不要这样做。只需按他们的名字使用它们,每次你不确定它们来自哪里时都在网上搜索。随着时间的推移,您将毫不费力地学习它们。

【讨论】:

谢谢——所以从上面和上面来看,很明显我已经问过一些不属于 c++ 的东西(但显然在 Java 中是可能的,所以之前可能有几个人我谁想做这样的事情)。有没有我可以在 C++ 中调用的函数来确定函数来自的标头? (是的,我知道存在互联网,但我也想在我的代码中这样做以供个人使用......) @neuronet:通过将 Java 引入其中,您再次混淆了 namespacesfiles 的概念。 Java 标准库以 C++ 所没有的方式组织成许多子命名空间:this 是您可以提出的有效观点。【参考方案3】:

如何指定或确定函数来自哪个头文件?

您通常在遇到问题时执行此操作,例如试图找出缺少符号的原因或发生标题冲突的位置。正如 Lightness Races in Orbit 和 Bolov 所指出的,这不是您通常在运行时所做的事情。

但如果你想这样做,请执行以下操作:

gcc -E t.c

如果t.c 是:

$ cat t.c
#include <stdio.h>

int main(int argc, char* argv[])

    return 0;

输出将类似于:

$ gcc -E t.c
# 1 "t.c"
# 1 "<command-line>"
# 1 "t.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 28 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
# 323 "/usr/include/features.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/predefs.h" 1 3 4
# 324 "/usr/include/features.h" 2 3 4
# 356 "/usr/include/features.h" 3 4
...
# 866 "/usr/include/stdio.h" 3 4
extern FILE *popen (__const char *__command, __const char *__modes) ;
extern int pclose (FILE *__stream);
extern char *ctermid (char *__s) __attribute__ ((__nothrow__));
# 906 "/usr/include/stdio.h" 3 4
extern void flockfile (FILE *__stream) __attribute__ ((__nothrow__));
extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__)) ;
extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__));
# 936 "/usr/include/stdio.h" 3 4

# 2 "t.c" 2

int main(int argc, char* argv[])

 return 0;

然后,通过grep 管道输出以找到感兴趣的函数。

【讨论】:

感谢您的建议。没有简单的函数可以打印出函数来自哪个标准头文件?例如,返回 'iostream' 的 header_name('std::cin')? 对于在标题中查找定义,我相信经常使用ctags。但是,我不使用它。我通常使用 IDE(只需右键单击 -> 转到定义)并查看打开的内容。如果我不使用 IDE,我会尝试快速搜索。如果搜索失败,我会使用grep 感谢您的帮助:不幸的是,我正在使用 code::blocks 并右键单击,但没有找到“转到定义”类型的帮助。我会去 code::blocks 论坛问问,如果我有任何回复,我会回来报告。

以上是关于如何确定函数来自哪个头文件?的主要内容,如果未能解决你的问题,请参考以下文章

vc++中getnameinfo函数在哪个头文件中

c语言中,为了使用scanf、printf函数,需要包含哪个头文件? 具体语句如何书写?

main函数包含在哪个头文件里,为啥使用main函数时不用先包含其所在的头文件

conio.h是哪个头文件?

WINDOWS操作系统下的C语言头文件存放在哪个目录中?

用Source Insight看Linux源代码,同一个函数会出现多重位置,怎么确定到底用的哪个呢?