You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C语言使用Makefile时全局变量重定义与未声明问题排查求助

解决C语言全局变量重复定义与未声明问题

你的问题核心是混淆了全局变量的「定义」和「声明」,下面一步步拆解问题并给出解决方案:

问题根源分析

  1. 链接错误(multiple definition):你最初在三个源文件里都定义了相同的全局变量,C语言中全局变量的定义会分配内存,多个文件定义同名全局变量会导致链接器找到多个相同符号,从而报错。
  2. 编译错误(undeclared):当只在main.c里保留定义时,comp_disc.cprint_res.c的编译器不知道这些变量的存在——编译器处理单个源文件时,看不到其他文件里的变量定义,所以报未声明。

正确的解决方法:分离声明与定义

最佳实践是用头文件统一声明全局变量,在单个源文件里定义它们,其他文件通过包含头文件来使用这些变量。

步骤1:创建全局变量头文件

新建globals.h,用extern声明所有需要共享的全局变量(extern告诉编译器:这些变量在其他地方已经定义,不用在这里分配内存):

#ifndef GLOBALS_H
#define GLOBALS_H

// 全局变量声明
extern double Mdisc;
extern double Cost_of_purchase;
extern double DiscTot;
extern double Sales_tax;
extern double Total_price;
extern char military;

#endif // GLOBALS_H

#ifndef是头文件卫士,防止头文件被重复包含导致重复声明错误。

步骤2:修改main.c保留变量定义

main.c里保留全局变量的定义(实际分配内存),并包含头文件:

#include <stdio.h>
#include "globals.h"  // 引入全局变量声明

// 函数原型
void compute_discount(void);
int print_results(void);

// 全局变量的定义(仅在这里做一次)
double Mdisc;
double Cost_of_purchase;
double DiscTot;
double Sales_tax;
double Total_price;
char military;

int main (void) {
	//Cost of purchase
	printf("Cost of purchase?\t\t$");
	scanf ("%lf",&Cost_of_purchase);

	//Military?
	printf("In military (y or n)?\t\t");
	scanf(" %c" ,&military);

	//calling for functions
	compute_discount();
	print_results();
}

步骤3:修改其他源文件包含头文件

comp_disc.cprint_res.c里去掉原来的变量定义,添加头文件包含:

修改后的comp_disc.c

#include <stdio.h>
#include "globals.h"  // 获取全局变量声明

//function to compute discount
void compute_discount(void){

	//compute military discount
	switch(military){
		case 'y':
		case 'Y':
			if(Cost_of_purchase > 150) {
				Mdisc = .15 * Cost_of_purchase;
			} else if (Cost_of_purchase < 150) {
				Mdisc = .10 * Cost_of_purchase;
			}
			break;
		case 'n':
		case 'N':
			Mdisc = 0;
			break;
		default:
			printf("Error: bad input\n");
	}

	//cost minus military discount
	DiscTot = Cost_of_purchase - Mdisc;
	//sales tax
	Sales_tax = .05 * DiscTot;
	//Total Calculated
	Total_price = DiscTot + Sales_tax;
}

修改后的print_res.c

#include <stdio.h>
#include "globals.h"  // 获取全局变量声明

//function to print results
int print_results(void){

	//if input is y Y then use below, this is not dependant on if military only if the letter is accepted
	switch(military){
		case 'y':
		case 'Y':
			printf("Military discount (15%%): \t$%.2f\n", Mdisc);
			printf("Discounted total: \t\t$%.2f\n", DiscTot);
			printf("Sales tax (5%%): \t\t$%.2f\n", Sales_tax);
			printf("Total: \t\t\t\t$%.2f\n", Total_price);
			break;
		//less information is given when n or N is used
		case 'n':
		case 'N':
			printf("Sales tax (5%%): \t\t$%.2f\n", Sales_tax);
			printf("Total: \t\t\t\t$%.2f\n", Total_price);
			break;
	}
	return(0);
}

步骤4:更新Makefile添加头文件依赖

修改Makefile,让每个.o文件依赖对应的头文件,这样头文件修改时会自动重新编译:

# target : dependencies
cwork7 : main.o comp_disc.o print_res.o
	gcc main.o comp_disc.o print_res.o -Wall -o cwork7

main.o : main.c globals.h
	gcc -c main.c -Wall

comp_disc.o : comp_disc.c globals.h
	gcc -c comp_disc.c -Wall

print_res.o : print_res.c globals.h
	gcc -c print_res.c -Wall

为什么这样能解决问题?

  • extern关键字负责声明变量:告诉编译器变量的类型和名称,不用分配内存。
  • 全局变量的定义(分配内存)只在一个文件中进行(这里是main.c),链接器只会找到一个符号,避免重复定义错误。
  • 头文件统一管理声明,避免在多个文件中重复写extern,提升代码可维护性。

内容的提问来源于stack exchange,提问作者Ivickt

火山引擎 最新活动