The Problem
When multiple source files include a header that defines global variables, the linker reports multiple definition errors. Consider a header file (main.h) that directly defines global arrays:
#ifndef __MAIN_H
#define __MAIN_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define max 100
struct student
{
char name[max];
char num[max];
char sex[max];
int chinese;
int mathematic;
int english;
int computer;
} s[5] = {
{"XiaoMing", "001", "boy", 80, 90, 80, 90},
{"XiaoWang", "002", "boy", 60, 80, 90, 50},
{"XiaoHong", "003", "girl", 85, 65, 75, 90},
{"XiaoChen", "004", "boy", 55, 65, 75, 80},
{"XiaoQing", "005", "girl", 90, 95, 98, 99}
};
struct User
{
char username[20];
char password[20];
} user[3] = {
{"Lucky", "001"},
{"Happy", "100"},
{"Find", "999"}
};
#endif
During compilation, each .cpp file that includes main.h sees the array definitions. The compiler allocates memory for s and user in every translation unit. When the linker combines all object files, it finds s and user defined more than once, producing errors like:
msvcrt.lib (std新城_000) : error LNK1169:找到一个或多个多重定义的符号
student.obj : error LNK2005: _s 已在 main.obj 中定义
student.obj : error LNK2005: _user 已在 main.obj 中定义
The same issue appleis to primitive global variables declared alongside the arrays.
Solution
Separate definition from declaration:
- Definition (allocates memory): placed in exactly one
.cppfile. - Declaration (no memory allocation): placed in the
.hfile usingextern.
Step 1: Modify the Header
Replace all array definitions with extern declarations:
#ifndef __MAIN_H
#define __MAIN_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define max 100
extern int g, h;
struct student
{
char name[max];
char num[max];
char sex[max];
int chinese;
int mathematic;
int english;
int computer;
};
struct User
{
char username[20];
char password[20];
};
// Declarations only — no memory allocated here
extern struct student s[5];
extern struct User user[3];
#endif
Step 2: Define Variables in One Source File
Choose a single .cpp file (typically main.cpp) and place the actual definitions there:
#include "main.h"
int g = 0;
int h = 5;
struct student s[5] = {
{"XiaoMing", "001", "boy", 80, 90, 80, 90},
{"XiaoWang", "002", "boy", 60, 80, 90, 50},
{"XiaoHong", "003", "girl", 85, 65, 75, 90},
{"XiaoChen", "004", "boy", 55, 65, 75, 80},
{"XiaoQing", "005", "girl", 90, 95, 98, 99}
};
struct User user[3] = {
{"Lucky", "001"},
{"Happy", "100"},
{"Find", "999"}
};
All other .cpp files simply #include "main.h" and access g, h, s, and user directly—no additional declarations needed.
How the Linker Resolves extern
The extern keyword tells the compiler: "This identifier is defined elsewhere; do not allocate memory for it here." During compilation, the compiler records the symbol reference. At link time, the linker searches all object files for the actual definition and resolves every reference to it. If no definition is found, the linker reports an unresolved symbol error. If more than one definition is found, it reports a multiple definition error.
This is the same mechanism used for global function prototypes declared in headers:
// In header: declares the function exists
extern void login(void);
extern void index(void);
// In one .cpp file: defines the function
void login(void)
{
// implementation
}
Scope of This Pattern
This fix applies to any variable or array declared at global scope. For local variables, extern has a different effect: it extends the variable's linkage to internal linking (with static) or external linking (without static), but the common use case in structured C projects is global data shared across multiple source files.
For a course project using a struct array to store student records, this approach works well. For larger-scale applications, consider moving data to a file-based or database-backed storage layer instead of relying on global arrays.