我对C和编译过程的基本知识最近变得生疏.我试图找出以下问题的答案,但我无法连接编译,链接和预处理阶段基础知识.快速搜索谷歌也没什么帮助.所以,我决定来到最终的知识来源:)
我知道:不应该在.h文件中定义变量.可以在那里宣布它们.
原因:因为头文件可能包含在多个位置,因此重新定义变量多次(链接器给出错误).
可能的解决方法:在头文件中使用header-guard并在其中定义变量.
它真的是一个解决方案:不.因为标题保护是用于预处理阶段.那就是告诉编译器这部分已经包含在内并且不再包含它.但是我们的多重定义错误来自链接器部分 - 在编译之后很久.
整件事让我对预处理和链接的工作方式感到困惑.如果已经定义了头部保护符号,我认为预处理将不包括代码.在那种情况下,不应该解决变量问题的多重定义吗?
这些预处理指令会在标题保护下重新定义编码过程,但是链接器仍会获得符号的多个定义,会发生什么?
C++如何包含通常命名的守卫?我倾向于看到这么多:
#ifndef FOO_H
#define FOO_H
// ...
#endif
Run Code Online (Sandbox Code Playgroud)
但是,我认为这不是很直观.如果没有看到文件名,就很难分辨出它的含义FOO_H和名称所指的含义.
什么是最佳做法?
我们都知道何时使用包括警卫,但何时不在我们的项目中使用它?
最近,我看到了一个混合编译项目(CUDA + GCC),一个头文件(CUDA文件)被故意留下而没有包括后卫.我只是好奇.
我一直在制作这样的文件:订单有意义吗?或者应该交换名称空间和#includes以及原因.
#ifndef CLASSNAME_H // header guards
#define CLASSNAME_H
#include "a.h" // includes in alphabetical order
#include "b.h" // user specified includes first
#include "c.h"
#include <vector> // then library includes
namespace MyNamespace
{
class ClassName
{
};
}
#endif
Run Code Online (Sandbox Code Playgroud) #include <iostream>
int main()
{
int value1 = 1, value2 = 10;
std::cout << "Min = " << std::min(value1,value2) <<std::endl;
std::cout << "Max = " << std::max(value1,value2)<< std::endl;
}
Run Code Online (Sandbox Code Playgroud)
据我所知,min和max函数的定义<algorithm>.
如果我没有告诉预处理器包含<algorithm>为什么代码仍然有效?
在使用.hpp/.cpp模板创建新类时,是否有可能(以及如何)在Eclipse CDT中自动生成的包含保护的名称中添加命名空间?
对我来说,Eclipse很好地生成了一个带有命名空间的新类,但是包含保护不包含命名空间,因此如果相同的头文件在两个不同的目录中存在两次,则只能包含一个.
在我的例子中,命名空间的名称,Eclipse项目名称和源目录的名称都是相同的,因此这些可以作为include guard的前缀.
我希望通过使用Eclipse/CDT创建一个新的C++类来自动生成include-guard,但是我找不到任何改变${include_guard_symbol}属性的方法.
我的愿望是带有名称空间前缀的include-guard,如下所示:
#ifndef NAMSPACE1_NAMESPACE2_HEADER_HPP
Run Code Online (Sandbox Code Playgroud)
但如果我使用#ifndef ${namespace_name}_${include_guard_symbol}它,它将产生:
namepace1::namespace2::_HEADER_HPP
Run Code Online (Sandbox Code Playgroud)
我怎样才能做到这一点?
在编写模板化类时,我喜欢将实现移动到另一个文件(myclass.tpp)中并将其包含在主标题(myclass.hpp)的底部.
我的问题是:我是否需要在.tpp文件中包含保护,或者将它们放在.hpp文件中是否足够?
示例代码:
myclass.hpp
#ifndef MYCLASS_HPP
#define MYCLASS_HPP
template<typename T>
class MyClass
{
public:
T foo(T obj);
};
//include template implemetation
#include "myclass.tpp"
#endif
Run Code Online (Sandbox Code Playgroud)
myclass.tpp
#ifndef MYCLASS_TPP //needed?
#define MYCLASS_TPP //needed?
template<typename T>
T MyClass<T>::foo(T obj)
{
return obj;
}
#endif //needed?
Run Code Online (Sandbox Code Playgroud) 我有几个头文件,归结为:
tree.h中:
#include "element.h"
typedef struct tree_
{
struct *tree_ first_child;
struct *tree_ next_sibling;
int tag;
element *obj;
....
} tree;
Run Code Online (Sandbox Code Playgroud)
和element.h:
#include "tree.h"
typedef struct element_
{
tree *tree_parent;
char *name;
...
} element;
Run Code Online (Sandbox Code Playgroud)
问题是它们都相互引用,因此树需要包含元素,元素需要包含树.
这不起作用,因为要定义"树"结构,元素结构必须已知,但要定义元素结构,必须知道树结构.
如何解决这些类型的循环(我认为这可能与'前向声明'有关?)?
当CLion创建一个头文件时,它会添加包含这样的保护字符串:
#ifndef PROJECTNAME_FILENAME_H
#define PROJECTNAME_FILENAME_H
/* ... code ... */
#endif //PROJECTNAME_FILENAME_H
Run Code Online (Sandbox Code Playgroud)
但我想要FILENAME_H没有PROJECTNAME_前缀.如何在CLION设置中更改它?
include-guards ×10
c++ ×6
c ×3
eclipse-cdt ×2
namespaces ×2
clion ×1
eclipse ×1
header-files ×1
linker ×1
templates ×1