C语言的重定义错误,求解

C语言中经常对见到重定义的错误,起码我写代码时会这样。
在看别人代码的时候,经常对看到一些自己喜欢的功能,想要把它们提取出来,写成一个头文件方便自己后面使用。
这个本来也不算多难的事情,但是你经常要去改动文件的组织结构,这样就会涉及到头文件的包含问题,很容易就碰到重定义错误,很让人沮丧。
别人的代码为了简便,直接将功能函数和main函数写在了一起,也就是说,他根本就不需要include。文件只有2个,EnumSymbols.h和EnumSymbols.cpp。

现在我想把main函数充EnumSymbols.cpp中拿到Main.cpp中,然后在Main.cpp中includeEnumSymbols.h文件。这样后续EnumSymbols.h和EnumSymbols.cpp文件可以作为一个功能库文件来用,会比较方便。但是出现了重定义错误,是在EnumSymbols.h中定义的结构体报的错。
比如这句:
// 系统模块信息
typedef struct _SYSTEM_MODULE_INFORMATION
{
ULONG Reserved[2];
ULONG Base;
ULONG Size;
ULONG Flags;
USHORT Index;
USHORT Unknown;
USHORT LoadCount;
USHORT ModuleNameOffset;
CHAR ImageName[256];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;

重复包含的原因其实我也是知道的。Main.cpp和EnumSymbols.cpp都要include EnumSymbols.h。这是2个cpp文件,所以使用 #ifdef #endif或者#pragma once 都是搞不定的,那个只能解决同一文件中的重复引用。现在重复包含是出现在2个cpp文件中的,报错在obj文件连接的时候出现。

有没有啥好方式给解决下这个问题?

重复定义是指编译时同一个定义多次给出或者连接时出现多个外部符号(外部函数和全局变量在不同实现文件中重复定义)。

#ifndef...#pragma once这些指令是用于防止同一个头文件在同一个实现文件中多次包含,这只能解决第一种冲突。

你的问题可能是函数或者全局变量的定义在整个程序中重复了。检查头文件中是否有全局变量定义(没有加extern的就是定义),有的话试试添加关键字static,或者吧定义写在.c文件里。从你的图片上来看,头文件里包含了几个指针变量定义,在这些指针变量定义前面添加关键字extern(如果有初始式去掉初始式)强制将定义改为声明,然后随便在一个实现文件中定义这些指针变量。

将全局变量定义或者函数定义放在头文件里容易导致连接错误,不要写这种代码。。。

结构体这种语法结构可以在不同实现文件中重复出现。追问

那如果要用到全局变量,要把它写在C文件中?

那全局变量的主要作用其实就是跨文件作用域来传递一些东西,写在C文件中,不太好在别的文件中引用吧。用的时候写extern进去?

感觉全局变量在C里用起来比较麻烦,有时候很顺手就会在头文件中写一些全局变量定义,然后到用的时候发现各种连接错误。

想知道有没有比较标准的处理全局变量的方式?感觉它用起来特麻烦。按照顺手的方式去写,写完了就错了。

追答

全局变量是不推荐使用的,尽量使用局部变量,这可以使错误局部化。

当必须使用全局变量时:
1.如果全局变量只在某个实现文件中发挥作用,则全局变量应该定义在该实现文件,并且为static变量,以此将该变量作用于限定为该文件。

2.如果全局变量被多个实现文件中使用,则可以将全局变量声明放在头文件中,并将定义单独放在一个实现文件中,以后其他需要这个全局变量的实现文件只需包含这个头文件即可直接使用。

声明全局变量的语法:
extern 类型 变量名;
定义全局变量的语法:
类型 变量名[= 初始式];
extern 类型 变量名 = 初始式;

标准的头文件一般只包括:
1.结构体等复合结构定义
2.函数声明
3.常量宏

全局变量是不推荐使用的,尽量使用局部变量,这可以使错误局部化。

当必须使用全局变量时:
1.如果全局变量只在某个实现文件中发挥作用,则全局变量应该定义在该实现文件,并且为static变量,以此将该变量作用于限定为该文件。

2.如果全局变量被多个实现文件中使用,则可以将全局变量声明放在头文件中,并将定义单独放在一个实现文件中,以后其他需要这个全局变量的实现文件只需包含这个头文件即可直接使用。

声明全局变量的语法:
extern 类型 变量名;
定义全局变量的语法:
类型 变量名[= 初始式];
extern 类型 变量名 = 初始式;

标准的头文件一般只包括:
1.结构体等复合结构定义
2.函数声明
3.常量宏

温馨提示:答案为网友推荐,仅供参考
第1个回答  2014-02-14
链接错误应该会提示重定义的符号名,你要查一下是哪个符号。可以肯定不是 SYSTEM_MODULE_INFORMATION 或者 PSYSTEM_MODULE_INFORMATION 重定义。应该是在EnumSymbols.h 里面定义了别的变量或者函数。类型重复定义不会在链接时候报错,只会在编译时报错。追问

嗯 我仔细看下报错。


因为是别人写的程序,而且对我来说比较复杂,所以看的时候就不是太明白。

对VC的include导致重定义错误一直比较头痛。


报错是这样的。我发现在EnumSymbol.h中有一些全局变量的定义,是不是它们导致的编译错误?

VC中结构重复包含是不是不会引起重定义错误?

只有全局变量会?

望君能释疑解惑。

追答

首先纠正一下,你这里遇到的不是编译错误而是链接错误(LNK\d+)。出现链接错误意味着编译完全正确。

就是这些全局变量的定义导致的链接错误。EnumSymbol.h 及其 include 的文件中,定义了 hProcess, pSymGetSymbolFile 等变量。这些变量在链接的时候找到了多个定义,因此出现了链接错误

结构重复包含会引起重定义错误,但这个是编译错误,例如在同一个 .h 或者 .cpp 文件中定义了两次 SYSTEM_MODULE_INFORMATION 结构体,这个在编译时会报重定义错误,而不是链接时。

只有在多个.c/.cpp 文件中定义的同名全局变量会导致链接时出现这种错误。

总之,你说的重定义错误包含了两种情况:编译时的和链接时的。编译时的是指在一个编译单元中出现了多次的符号;链接时的是指编译成功后,在不同的编译单元中出现多次的符号

第2个回答  2014-02-14
在你的头文件首尾加上这样的预处理:

#ifndef _ENUMSYMBOLS_H_
#define _ENUMSYMBOLS_H_

........ // 你的原始头文件内容

#endif追问

已加。
如果没加会出编译错误。
我这个是链接错误,报错在obj里。

第3个回答  2014-02-15
楼主提高悬赏,我给答案,知识是无价的
第4个回答  2014-02-14
不懂,这样的一个结构体定义同时include在两个cpp里应该是没有任何问题的啊?追问

额 VC学的比较水,野路子出来的,所以我自己都朦朦胧胧的。
之前查过一些资料,有说是不同文件中的重复包含导致的。
结构体的我还真是第一个碰到这个情况,你可以确定结构体可以在不同cpp文件中重复包含?
VC的include真是很纠结···

相似回答