读书人

运用惯IDE编译知识匮乏求教

发布时间: 2013-04-02 12:35:26 作者: rapoo

使用惯IDE,编译知识匮乏,求教
之前使用VS,做测试的代码,非常喜欢写在一个project里。每次要测试什么代码了,新建一个.h文件

test.h

#pragma once
namespace mytest
{
class A
{
public:
print()
{

}
};

void test()
{
A().print();//测试代码
}
}


然后在main.cpp文件里包含这个头文件

#include "test.h"

void main()
{
mytest::test();
}


这种感觉很方便。转到linux下,用eclipse,这样写的话,会报重复定义什么的错。也问了人了。大家都说,应该再建个.cpp文件,把定义的东西写在.cpp里。(实际工作肯定是这样,但对于测试……)



我问大家个最简单的问题吧
extern
之前已经问过一次了。还疑惑,大家说,用它,为了防止重复定义。
举例:
a.h中
extern int value;
b.h中
extern int value;
在c.cpp中定义
int value = 999;


这里有2点疑惑,一,既然a.h中已经声明了int value;,b.h中为什么还要申明,b.h中include "a.h"不就行了?
二、即使有好多头文件套来套去,不是有
#ifndef AAA
#define AAA
int value;
#endif
吗?
这不能防止重复定义吗?
[解决办法]
保护性的 ifndef define 是为了防止在一个文件内重复包含,

编译器真正关心的是 c/cpp 文件, h 在预处理阶段就被消耗了.

如果在两个文件内包含这个 h,
那么, 两个文件内就都包含
void test()
{
A().print();//测试代码
}
的实现代码.
[解决办法]
引用:
之前使用VS,做测试的代码,非常喜欢写在一个project里。每次要测试什么代码了,新建一个.h文件

test.h
#pragma once
namespace mytest
{
class A
{
public:
print()
{

}
};

void test()
{
A().print();//测试代码
}
}


然后在main.cpp文件里包含这个头文件

#include "test.h"

void main()
{
mytest::test();
}


这种感觉很方便。转到linux下,用eclipse,这样写的话,会报重复定义什么的错。也问了人了。大家都说,应该再建个.cpp文件,把定义的东西写在.cpp里。(实际工作肯定是这样,但对于测试……)



我问大家个最简单的问题吧
extern
之前已经问过一次了。还疑惑,大家说,用它,为了防止重复定义。
举例:
a.h中
extern int value;
b.h中
extern int value;
在c.cpp中定义
int value = 999;


这里有2点疑惑,一,既然a.h中已经声明了int value;,b.h中为什么还要申明,b.h中include "a.h"不就行了?
二、即使有好多头文件套来套去,不是有
#ifndef AAA
#define AAA
int value;
#endif
吗?
这不能防止重复定义吗?
是个很蛋疼的问题,你那段代码是没有问题,但是问题出现在引用上,可能在你不经意引用的时候,出现了文件被重复包含,导致重复被定义,解决办法,采用cpp文件比较合理,用到的时候,extern 就行了。
[解决办法]
问题1:在eclipse中编译时,如果你建立了C++工程,是没问题的。不过首先需要你把头文件需要引用的其他头文件补齐。如#include <stdio.h> #include <stdlib.h>等。
问题2:要看你实际的用法了。如果你在头文件中进行了函数或类的实现的话,必须要声明的。如果仅仅是类或函数的声明,则不需要。只需要在实现函数或类中引用调用了你定义的value时,在该文件的上方做一下extern声明就好了

[解决办法]
引用:
一,既然a.h中已经声明了int value;,b.h中为什么还要申明,b.h中include "a.h"不就行了?

可以。不过有时候需要 include b.h 又不能或不希望出现一个 value 的声明,这种把 b.h 和 a.h 困死的做法就不好使了。

引用:
二、即使有好多头文件套来套去,不是有
#ifndef AAA
#define AAA
int value;
#endif
吗?
这不能防止重复定义吗?

这个和 extern 的效果不一样。比如有 c.cpp 定义 int value; a.h, b.h 包含 extern int value; a.cpp, b.cpp 各自 include a.h, b.h。那么整个程序中只有一个 value 的实体,定义在 c.cpp 中,其他所有对 value 的读写都影响 c.cpp 中的 value。


如果按你给的方法,a.h 中定义 value,其他文件 include a.h。那么程序中会有多个 value 的定义,那个 cpp 包含了 a.h,那个 cpp 就有一个叫 value 的 int 变量,其他部分程序读写的只是本编译单元内定义的 value 变量。包含关系复杂以后,很容易就搞不清到底在修改那个 value 变量了。
简而言之,少用 global variables.
[解决办法]
第二个问题,使用extern修饰对象,是为了在各个不同的c/cpp文件中操作同一个对象。这是在在link阶段由linker实现的。如果使用#ifdef,各个c/cpp文件操作的对象其实是独立的。
[解决办法]
LZ在VS中的的实践就是错的。
.h中应该只放声明,没有定义。

一,既然a.h中已经声明了int value;,b.h中为什么还要申明,b.h中include "a.h"不就行了?
// 对的,但是b中声明也不为错。最好的做法是,以逻辑为单位进行声明。
// 即value为某功能所用,则以该功能为逻辑单位,封装到一个.h中,其他需要此逻辑功能的,就引用该头文件

二、即使有好多头文件套来套去,不是有
#ifndef AAA
#define AAA
int value;
#endif
吗?
这不能防止重复定义吗?
// 说明LZ没明白重复定义怎么来的。假定有此a.h,但是我同时有两个.c包含了它,比如foo.c和bar.c,那么foo.c中就有个int value;的定义,同时bar.c中也有一个int value;的定义,这样就是value的重复定义。
// 注意那是防止重复包含,而不是重复定义。不要混了。

[解决办法]
编辑的基本单元是“文件”
也就是说 编译器是针对每个.cpp分别编译的 然后再链接
extern int value; 只是说明这个int value在其他的地方被定义,在本次编译单元中,你只需要知道其类型(是int)即可,在链接的时候在其他文件去链接
而int value; 这里就不是一个声明了,而是一个定义,只不过value没有显示初始化,如果在全局区,则编译器可以默认将其构造为0,而在栈上,则是一个“脏数据”,如果你每个.cpp都引用同样同样的.h,其中包含同样的int value,这里在编译时没问题,但链接时就是重复定义了,违背了ODR( one definition Rule)

读书人网 >C++

热点推荐