详细了解 static 和 extern 关键字的用法
C语言 static 和 extern关键字
static
一、 static
函数 和 普通函数 区别
总的来说,static
函数和普通函数的区别就是体现在作用域上面。static
函数只是在本文件起作用。不可以被其他文件调用。先举个例子
例一
math.c
static int add(int a,int b)
{
return a+b;
}
main.c
#include <stdio.h>
int main() {
int a = 10,b=22;
printf("%d!\n",add(a,b));
return 0;
}
对上面文件用gcc
进行编译
$ gcc main.c math.c
结果如下
main.c:15:20: warning: implicit declaration of function 'add' is invalid in C99
[-Wimplicit-function-declaration]
printf("%d!\n",add(a,b));
^
1 warning generated.
Undefined symbols for architecture x86_64:
"_add", referenced from:
_main in main-eaa78d.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
很明显的错误就是main.c
文件中的函数 add
未定义。
我们做一下修改,加一个.h头文件
math.h
static int add(int a,int b);
在main.c
中引入
#include <stdio.h>
#include "math.h"
int main() {
int a = 10,b=22;
printf("%d!\n",add(a,b));
return 0;
}
再次使用gcc
进行编译
$ gcc main.c math.c
结果是一样的
./math.h:8:12: warning: function 'add' has internal linkage but is not defined
[-Wundefined-internal]
static int add(int a,int b);
^
main.c:15:20: note: used here
printf("%d!\n",add(a,b));
^
1 warning generated.
Undefined symbols for architecture x86_64:
"_add", referenced from:
_main in main-c5f44a.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
这说的是add
函数已经声明了,但是在main.c
中并没有定义(虽然在 math.c中有定义,但是函数是static
类型的,只在math.c
文件中可见)。
有两种方式修改
一)将math.c
中的函数改成普通函数
int add(int a,int b)
{
return a+b+10;
}
gcc
编译会产生警告
main.c:15:20: warning: implicit declaration of function 'add' is invalid in C99
[-Wimplicit-function-declaration]
printf("%d!\n",add(a,b));
^
1 warning generated.
但是程序是可以正常执行的。要去除警告可以在math.h
中声明普通函数,然后在main.c
中引入math.h
int add(int a,int b);
二)在main.c
中定义add()
函数
#include <stdio.h>
static int add(int a,int b)
{
return a+b;
}
int main() {
int a = 10,b=22;
printf("%d!\n",add(a,b));
return 0;
}
千万注意的是,不可以同时在两个文件中定义普通的add
函数。例如
例二
math.c
int add(int a,int b)
{
return a+b+10;
}
main.c
#include <stdio.h>
int add(int a,int b)
{
return a+b;
}
int main() {
int a = 10,b=22;
printf("%d!\n",add(a,b));
return 0;
}
这样是会报错的,函数被重复定义。所以说,从另一方面,static
允许在不同文件中定义同名函数,这也是static
函数除作用域之外的另一用途。
二、static
变量 和 普通变量区别
static
变量和static
函数异曲同工,也是对作用域的限定。
extern
一、变量前加extern
关键字
对于函数有声明
和定义
两步。同样对于变量严格来说也是分声明
和定义
。定义一个变量就要为其分配内存并赋值。如果没指定值则根据变量类型赋相应的默认值。
int var1; // 相当于是 声明和定义合成为一步
extern int var2; // 仅仅是声明
也就是说在变量前面如果加上了extern
关键字,对于这个变量来说只是进行了声明并没有定义。下面举几个例子进行对extern
的用法进行说明
例一
main.c
#include <stdio.h>
int var1;
extern int var2;
int main()
{
var1 = 11;
var2 = 12;
printf("var1=%d; var2=%d\n",var1,var2);
return 0;
}
gcc
进行编译
$ gcc main.c
Undefined symbols for architecture x86_64:
"_var2", referenced from:
_main in main-179d3c.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
链接的时候没有找到变量var2
。因为var2
只是进行了声明,并没有定义,所以编译能通过,到了链接的时候就找不到了。
例二
main.c
#include <stdio.h>
int var1 = 11;
extern int var2 = 12;
int main() {
printf("var1=%d; var2=%d\n",var1,var2);
return 0;
}
gcc
进行编译
$ gcc main.c
main.c:5:12: warning: 'extern' variable has an initializer [-Wextern-initializer]
extern int var2 = 12;
^
1 warning generated.
只是一个警告,程序是可以正确执行的。也就是说 extern int var2 = 12
这种方式也是对变量进行了定义,但这是不合规则的,所以给你个警告。
extern
主要是对外部变量进行引用。所以正确合规的用法举例如下
例三
math.c
int var = 12;
main.c
#include <stdio.h>
extern int var;
int main()
{
printf("var = %d\n",var);
return 0;
}
gcc
进行编译
$ gcc main.c math.c
没有问题。 因为 var 变量是进行了定义的。 所以在main.c
中是可以找到var
变量的。
例四
math.c
extern int var = 12;
main.c
#include <stdio.h>
extern int var;
int main()
{
printf("var = %d\n",var);
return 0;
}
gcc
进行编译
$ gcc main.c math.c
static/math.c:61:12: warning: 'extern' variable has an initializer [-Wextern-initializer]
extern int var = 12;
^
1 warning generated.
也是可以通过的,只是多了一个警告。参照 例二
总的来说,只要是一个全局变量进行了定义。在其他文件中通过extern
关键字就可以进行引用。
二、extern
函数
函数默认都是extern
类型的。也就是说函数前面没有static
关键字修饰,那就都是extern
int add(int a, int b);
// 等价于
extern int add(int a, int b);
上面关于 extern 修饰的变量,必须要是定义的全局变量,在其他文件中才能通过 extern 进行引用。 函数内定义的变量是没法被其他文件进行引用的。
相关文章
Do you understand JavaScript closures?
发布时间:2025/02/21 浏览次数:108 分类:JavaScript
-
The function of a closure can be inferred from its name, suggesting that it is related to the concept of scope. A closure itself is a core concept in JavaScript, and being a core concept, it is naturally also a difficult one.
Do you know about the hidden traps in variables in JavaScript?
发布时间:2025/02/21 浏览次数:178 分类:JavaScript
-
Whether you're just starting to learn JavaScript or have been using it for a long time, I believe you'll encounter some traps related to JavaScript variable scope. The goal is to identify these traps before you fall into them, in order to av
How much do you know about the Prototype Chain?
发布时间:2025/02/21 浏览次数:150 分类:JavaScript
-
The prototype chain can be considered one of the core features of JavaScript, and certainly one of its more challenging aspects. If you've learned other object-oriented programming languages, you may find it somewhat confusing when you start
Vue - An In-Depth Guide to Lifecycle Hooks
发布时间:2025/02/21 浏览次数:117 分类:Vue
-
Vue has many lifecycle hooks, and it can be confusing to understand the meaning or purpose of each one. In this article, we will explain the function of each lifecycle hook and how to use them.
Solution for Flickering During Vue Template Parsing
发布时间:2025/02/21 浏览次数:103 分类:Vue
-
Solution for Flickering During Vue Template Parsing, Recently, while working on a project, I noticed that when the internet speed is slow, the screen flickers and the expression message appears. This happens because when the internet speed i
Pandas read_csv()函数
发布时间:2024/04/24 浏览次数:254 分类:Python
-
Pandas read_csv()函数将指定的逗号分隔值(csv)文件读取到 DataFrame 中。
Pandas loc vs iloc
发布时间:2024/04/24 浏览次数:837 分类:Python
-
本教程介绍了如何使用 Python 中的 loc 和 iloc 从 Pandas DataFrame 中过滤数据。
在 Pandas 中使用 stack() 和 unstack() 函数重塑 DataFrame
发布时间:2024/04/24 浏览次数:1289 分类:Python
-
本文讨论了 Pandas 中 stack() 和 unstack() 函数的使用。