英文:
Should I use extern?
问题
I have the following files:
- pass_args.c
- pass_args.h
- kbd.c
- kbd.h
- main.c
There are 3 global variables that I would need to use: freq, amp and waveforms.
Should I declare those variables in every .h files by using extern and define the variable in one of the .c file OR create a global_variable.h, declare those variables in the global_variable.h and include this global_variable.h in every .c files.
Here is the minimal reproducible example:
change_freq.c
#include "change_freq.h"
void increment_freq(double *frequency)
{
(*frequency)++;
if (*frequency == 1)
{
amp++;
}
}
change_freq.h
#ifndef CHANGE_FREQ_H
#define CHANGE_FREQ_H
#include "global_variables.h"
void increment_freq(double *frequency);
#endif
global_variables.h
#ifndef GLOBAL_VARIABLES_H
#define GLOBAL_VARIABLES_H
double freq;
double amp;
#endif
main.c
#include "global_variables.h"
#include "change_freq.h"
int main()
{
freq = 0;
increment_freq(&freq);
printf("Hello World!\n");
printf("freq %lf\n", freq);
printf("amp %lf\n", amp);
return 0;
}
英文:
I have the following files:
- pass_args.c
- pass_args.h
- kbd.c
- kbd.h
- main.c
There are 3 global variables that I would need to use: freq, amp and waveforms.
Should I declare those variables in every .h files by using extern and define the variable in one of the .c file OR create a global_variable.h, declare those variables in the global_variable.h and include this global_variable.h in every .c files.
Here is the minimal reproducible example:
change_freq.c
#include "change_freq.h"
void increment_freq(double *frequency)
{
(*frequency)++;
if (*frequency == 1)
{
amp++;
}
}
change_freq.h
#ifndef CHANGE_FREQ_H
#define CHANGE_FREQ_H
#include "global_variables.h"
void increment_freq(double *frequency);
#endif
global_variables.h
#ifndef GLOBAL_VARIABLES_H
#define GLOBAL_VARIABLES_H
double freq;
double amp;
#endif
main.c
#include "global_variables.h"
#include "change_freq.h"
int main()
{
freq = 0;
increment_freq(&freq);
printf("Hello World!\n");
printf("freq %lf\n", freq);
printf("amp %lf\n", amp);
return 0;
}
答案1
得分: 1
这是你应该做的:
change_freq.c
#include "change_freq.h"
#include "global_variables.h" // <<< 添加这一行
void increment_freq(double frequency)
{
frequency++;
if (frequency == 1)
{
amp++;
}
}
change_freq.h
#ifndef CHANGE_FREQ_H
#define CHANGE_FREQ_H
// #include "global_variables.h" <<< 删除这一行
void increment_freq(double frequency);
#endif
global_variables.h
#ifndef GLOBAL_VARIABLES_H
#define GLOBAL_VARIABLES_H
extern double freq; // <<< 在这里加上 extern
extern double amp;
#endif
main.c
#include <stdio.h>
#include "global_variables.h"
#include "change_freq.h"
double freq; // <<< 在这里定义你的全局变量
double amp;
int main()
{
...
英文:
Your code is almost looks fine.
This is what you should do:
change_freq.c
#include "change_freq.h"
#include "global_variables.h" // <<< add this line
void increment_freq(double frequency)
{
frequency++;
if (frequency == 1)
{
amp++;
}
}
change_freq.h
#ifndef CHANGE_FREQ_H
#define CHANGE_FREQ_H
// #include "global_variables.h" <<< remove this line
void increment_freq(double frequency);
#endif
global_variables.h
#ifndef GLOBAL_VARIABLES_H
#define GLOBAL_VARIABLES_H
extern double freq; // << put extern here
extern double amp;
#endif
main.c
#include <stdio.h>
#include "global_variables.h"
#include "change_freq.h"
double freq; // << define your global variables here
double amp;
int main()
{
...
答案2
得分: 0
这是一个用于复制你的项目设置的脚本(在空目录中运行):
#!/bin/sh -eu
cat > global_variables.h <<EOF
#ifndef GLOBAL_VARIABLES_H
#define GLOBAL_VARIABLES_H
double freq;
double amp;
#endif
EOF
cat > change_freq.h <<EOF
#ifndef CHANGE_FREQ_H
#define CHANGE_FREQ_H
#include "global_variables.h"
void increment_freq(double *frequency);
#endif
EOF
cat > change_freq.c <<EOF
#include "change_freq.h"
void increment_freq(double *frequency)
{
(*frequency)++;
if (*frequency == 1)
{
amp++;
}
}
EOF
cat > main.c <<EOF
#include "global_variables.h"
#include "change_freq.h"
#include <stdio.h> ///ADD!
int main()
{
freq = 0;
increment_freq(&freq);
printf("Hello World!\n");
printf("freq %lf\n", freq);
printf("amp %lf\n", amp);
return 0;
}
EOF
保持这种方式,只有在你的编译器和链接器支持并隐式允许所谓的公共变量时,它才能编译和运行(cc *.c && ./a.out
),这允许未初始化的全局变量(double freq; double amp;
)在多个翻译单元中被暂时定义,然后由链接器合并它们。对于gcc/clang,你可以使用-fcommon
显式请求这个非标准特性。(所以gcc -fcommon *.c && ./a.out
应该能工作)。
一个便携的解决方案是在头文件中这样做:
extern double freq, amp;
在一个C文件中这样做:
/*no-extern*/ double freq, amp;
(你看,全局范围的double freq;
double amp;
,没有extern
和初始化器都是声明和暂定定义。暂定定义意味着你可以重新定义它们一次,之后它们就完成了(并且非暂定的重新定义尝试会变成错误),和/或者暂时重新定义它们。如果没有提供初始化器,它们默认会被零初始化,并在编译单元结束时完成。-fcommon
扩展(链接器也需要支持)允许你将暂定全局变量的完成从编译单元的末尾延迟到链接时。这是来自B的传统功能,如果我没记错的话。它依赖于将暂定全局变量分类为一种称为公共符号的特殊类型的链接器符号,其工作方式与标准C暂定定义相同,只是跨所有被链接的文件而不仅仅是单个翻译单元。)
英文:
Here's a script to reproduce your project setup (run in an empty directory):
#!/bin/sh -eu
cat > global_variables.h <<EOF
#ifndef GLOBAL_VARIABLES_H
#define GLOBAL_VARIABLES_H
double freq;
double amp;
#endif
EOF
cat > change_freq.h <<EOF
#ifndef CHANGE_FREQ_H
#define CHANGE_FREQ_H
#include "global_variables.h"
void increment_freq(double *frequency);
#endif
EOF
cat > change_freq.c <<EOF
#include "change_freq.h"
void increment_freq(double *frequency)
{
(*frequency)++;
if (*frequency == 1)
{
amp++;
}
}
EOF
cat > main.c <<EOF
#include "global_variables.h"
#include "change_freq.h"
#include <stdio.h> ///ADD!
int main()
{
freq = 0;
increment_freq(&freq);
printf("Hello World!\n");
printf("freq %lf\n", freq);
printf("amp %lf\n", amp);
return 0;
}
EOF
With it being like this it should compile and run (cc *.c && ./a.out
) if and only if your compiler and linker support and implicitly allow so called common variables, which allow uninitialized global variables (double freq; double amp;
) to be tentatively defined in multiple translation units with the linker then merging them. For gcc/clang you can explicitly request this nonstandard feature with -fcommon
.
(So gcc -fcommon *.c && ./a.out
should work).
A portable solution would be to do
extern double freq, amp;
in the header, and
/*no-extern*/ double freq, amp;
in one of the C files.
(You see, double freq;
double amp;
at global scope without both extern
and initializers are both declarations and tentative definitions. Tentative definitions mean that you can redefine them with initializers once, after which they're finished (and non-tentative redefining attempts become errors), and/or tentatively redefine them. If no initializer is ever given, they're zero-initialized by default and finished by the end of the compilation unit. The (fairly common) -fcommon
extension (also needs support by the linker) allows you to extend this notion of tentative globals to multiple translation units by postponing the finishing of tentative globals from the end of the compilation unit to link time. It is a legacy feature from B, if I remember correctly. It relies on tentative globals being classed as a special type of linker symbol called a common symbol, which works the same as the standard C tentative definition except across all files being linked rather than just a single translation unit.)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论