详细了解 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 进行引用。 函数内定义的变量是没法被其他文件进行引用的。
相关文章
Oracle 的 decode 函数在 MySQL 中的等价物
发布时间:2023/05/09 浏览次数:115 分类:MySQL
-
本篇文章介绍了三种替代实现,我们可以将它们用作 MySQL 中 Oracle 的 decode() 函数的等价物。 为此,我们将使用 IF()、CASE 以及 FIELD() 和 ELT() 的组合。
更改 MySQL 服务器中的 max_allowed_packet Size
发布时间:2023/05/09 浏览次数:142 分类:MySQL
-
本篇文章介绍如何更改 MySQL 服务器中的 max_allowed_packet 大小。 为了了解这一点,我们将使用两个操作系统,Windows 10 和 Linux (Ubuntu)。
MySQL 修复 Data Is Truncated for a Column 错误
发布时间:2023/05/09 浏览次数:72 分类:MySQL
-
本文介绍 MySQL 错误 Data is truncated for a column 的可能原因和解决方法。修复数据因 MySQL 中的列错误而被截断
MySQL 错误 Error Server PID File Could Not Be Found 解决
发布时间:2023/05/09 浏览次数:98 分类:MySQL
-
在这篇文章中,我们将研究错误! Error Server PID File Could Not Be Found! 在 MySQL 及其解决方案中有充分的解释。
MySQL ForEach 循环
发布时间:2023/05/08 浏览次数:140 分类:MySQL
-
本篇文章介绍如何在一条语句中使用 INSERT、SELECT、WHERE 和 JOIN 模拟 MySQL 中的 foreach 循环。
使用 JDBC 连接到 MySQL 数据库
发布时间:2023/05/08 浏览次数:82 分类:MySQL
-
本文讨论 JDBC 以及使用 JDBC 连接数据库的要求。 我们还查看了一个示例,以了解如何实现 Java 代码来连接 MySQL 数据库。MySQL 为使用 Java 编程语言和 MySQL Connector/J 开发的应用程序提供连接。
遍历 MySQL 表的所有行
发布时间:2023/05/08 浏览次数:161 分类:MySQL
-
本篇文章介绍了如何使用 WHILE 和 CURSOR 遍历 MySQL 表的所有行。遍历 MySQL 表的所有行
在 C 语言中使用 typedef enum
发布时间:2023/05/07 浏览次数:181 分类:C语言
-
本文介绍了如何在 C 语言中使用 typedef enum。使用 enum 在 C 语言中定义命名整数常量 enum 关键字定义了一种叫做枚举的特殊类型。