迹忆客 专注技术分享

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

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

作者:迹忆客 时间:2021/05/10 浏览次数:

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

除非注明转载,本站文章均为原创,欢迎转载,转载请以链接形式注明出处

本文地址:

迹忆客

专注技术分享,项目实战分享!

技术宅 乐于分享 7年编程经验
社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

热门文章

热门标签

C