【发布时间】:2021-03-22 00:38:45
【问题描述】:
我是 C++ 新手,并试图了解预处理、编译和链接步骤是如何工作的。我在尝试使用 gflgas library 库时偶然发现了一个有趣的行为。
代码
以下是我在这里的示例中使用的代码:
#include <iostream>
#include <gflags/gflags.h>
DEFINE_string(name, "Tugberk", "Name of the person to greet");
int main(int argc, char *argv[]) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
std::cout << "Hello " << FLAGS_name << std::endl;
}
如您所见,我正在使用gflags:: 来联系ParseCommandLineFlags 功能。我假设 gflags 这里是命名空间(但我很确定我在这里错了,稍后会详细介绍)。
编译
我已经运行了以下命令来编译这段代码:
我调用
cc1plus的原因是模仿g++步骤来创建.s文件,以便我最终可以使用它通过汇编程序创建.o文件。我无意直接调用cc1plus。
/usr/lib/gcc/x86_64-linux-gnu/9/cc1plus -quiet -v -imultiarch x86_64-linux-gnu -D_GNU_SOURCE main.cpp -quiet -dumpbase main.cpp -mtune=generic -march=x86-64 -auxbase main -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o /tmp/ccFyWgz8.s
然后,我使用as 命令生成一个.o 文件,以便我可以使用nm llvm 符号表转储器检查它。
as -v --64 -o /tmp/ccONcT86.o /tmp/ccFyWgz8.s
我观察到的
然后我在能够生成的.o 文件上使用nm,此时我观察到ParseCommandLineFlags 函数的命名空间更改为google:
# nm -C /tmp/ccONcT86.o
0000000000000000 V DW.ref.__gxx_personality_v0
U _GLOBAL_OFFSET_TABLE_
00000000000001a0 t _GLOBAL__sub_I__ZN3fLS10FLAGS_nameB5cxx11E
U _Unwind_Resume
000000000000006f t __static_initialization_and_destruction_0(int, int)
0000000000000000 B fLS::FLAGS_name[abi:cxx11]
0000000000000000 W fLS::StringFlagDestructor::StringFlagDestructor(void*, void*)
0000000000000000 W fLS::StringFlagDestructor::StringFlagDestructor(void*, void*)
0000000000000000 n fLS::StringFlagDestructor::StringFlagDestructor(void*, void*)
0000000000000000 W fLS::StringFlagDestructor::~StringFlagDestructor()
0000000000000000 W fLS::StringFlagDestructor::~StringFlagDestructor()
0000000000000000 n fLS::StringFlagDestructor::~StringFlagDestructor()
0000000000000000 W fLS::dont_pass0toDEFINE_string[abi:cxx11](char*, char const*)
0000000000000060 b fLS::FLAGS_noname
0000000000000070 b fLS::d_name
0000000000000068 b fLS::o_name
0000000000000020 b fLS::s_name
U google::FlagRegisterer::FlagRegisterer<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(char const*, char const*, char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*)
U google::ParseCommandLineFlags(int*, char***, bool)
U std::allocator<char>::allocator()
U std::allocator<char>::~allocator()
U std::ostream::operator<<(std::ostream& (*)(std::ostream&))
U std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&)
U std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
U std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()
U std::ios_base::Init::Init()
U std::ios_base::Init::~Init()
U std::cout
U std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)
0000000000000000 r std::piecewise_construct
0000000000000008 b std::__ioinit
U std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
U std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
0000000000000000 W operator delete(void*, void*)
0000000000000000 W operator new(unsigned long, void*)
U __cxa_atexit
U __dso_handle
U __gxx_personality_v0
U __stack_chk_fail
0000000000000000 T main
检查gflags源代码后,我可以在以下两个地方看到这可能来自:
- https://github.com/gflags/gflags/blob/827c769e5fc98e0f2a34c47cef953cc6328abced/src/gflags.h.in#L97
- https://github.com/gflags/gflags/blob/827c769e5fc98e0f2a34c47cef953cc6328abced/src/gflags_declare.h.in#L41-L43
当我检查 gflags_declare.h 文件的安装版本时,我可以看到命名空间被定义为 google。
// ---------------------------------------------------------------------------
// Namespace of gflags library symbols.
#define GFLAGS_NAMESPACE google
问题
我假设gflags::ParseCommandLineFlags 语句上下文中的gflags 是命名空间,但似乎不是。这是从哪里来的,为什么编译器对此感到满意?编译器是如何知道将gflags:: 替换为google:: 的?
【问题讨论】:
-
这就是
#define预处理器指令的作用——类似于宏替换。 -
@1201ProgramAlarm 这是有道理的,但我不确定编译器是如何知道将我的代码中的
gflags::部分替换为第一部分的。另一种问这个问题的方法是编译器如何通过声明gflags::知道我指的是什么?是不是因为头文件叫gflags.h? -
@Ron 我无法从该文档中弄清楚在我的示例中如何解决
gflags。您能否指出具体的措辞? -
@Ron 这对我来说非常有意义。我正在努力的是
GFLAGS_NAMESPACE根本没有在我的代码中使用,它在库头文件中使用。所以,我无法理解我的代码中的gflags::引用如何被解释为“用'google'替换它”。 -
另一种可能性是命名空间别名,如
namespace gflags=google;或更巧妙的namespace gflags=GFLAGS_NAMESPACE;
标签: c++ compilation g++