迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 编程语言 > C语言 >

详细了解 static 和 extern 关键字的用法

作者:迹忆客 最近更新:2023/05/09 浏览次数:

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 进行引用。 函数内定义的变量是没法被其他文件进行引用的。

上一篇:没有了

下一篇:C 线程资源释放问题

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

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 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 关键字定义了一种叫做枚举的特殊类型。

C 语言中的静态变量

发布时间:2023/05/07 浏览次数:151 分类:C语言

本文介绍了如何在 C 语言中使用静态变量。在 C 语言中使用 static 变量在函数调用之间保存变量值

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便