天天看点

有关static和extern关键字

@ 有关static和extern关键字

@ MSDN

@ uselessstest

@ 2010.6.11

以下程序的编译,链接均采用VC6.0的编译器, 连接器.

以下面的程序为例

#include <stdio.h>

extern int i;

extern int j;

j = 1;

i = 1;

extern void f();

int main()

{

    static int i;

    int j = 10;

    f();

    printf("%d/n", i);

    printf("%d/n", j);

    return 0;

}

void f()

{

    i++;

    printf("%d/n", i);

}

输出结果是:

2

10

分析其运行过程.

extern int i;   // 此处是声明了变量i, 并不是对static int i的extern.

extern int j;   // 同样也是声明了变量j, 也不是对int j的extern.

j = 1;          // 这是对变量j的赋值,  也就是定义.

i = 1;          // 对变量i的赋值,  具体来说这里叫定义.

先来看上面的,  为什么一定要在这里赋值.

因为extern int i; extern int j只是声明了i和j, 声明是不开辟存储空间的, 只有定义才会.

因此下面必须要有定义.

下面这个程序是错误的.

extern int i;

void main()

{

    i = 10;         // 全局变量的赋值必须在任何函数外面.

}

再一点是, 赋值的时候必须是常量表达式.   如下的程序是错误的.

extern int i;

extern int j;

i = 10;

j = i;       // j的初始化必须用常量表达式.

void main()

{

}

再接着看下面的语句.

extern void f();    // 让下面的f函数在这里可见,  extern引用.  没什么好说的.

再就是main函数

第一句static int i;  // 这句让外面的那个i在main函数里不可见了.

int j = 10;   // 这句也让刚才在外面定义的j在main函数里不可见了.

接着调用f函数.

f函数里的第一个语句

i++;       // 这里的i应该是i=1; 所定义的i, 于是这里i的值变为2

printf("%d/n", i);  // 打印出的值也变为2.

于是回到main函数.

接着打印i, j, 这里的i和j就是static int i, 和 int j = 10; 里定义的i和j了.

.

对上面的程序做如下改变.

将f函数放到另外一个文件里, 命名为f.c

------------------- file test.c -----------------

#include <stdio.h>

extern int i;

extern int j;

j = 1;

i = 1;

extern void f();

int main()

{

    static int i;

    int j = 10;

    f();

    printf("%d/n", i);

    printf("%d/n", j);

    return 0;

}

------------- file f.c ------------------

#include <stdio.h>

extern int i;             // 引用test.c文件里的i

void f()

{

    i++;

    printf("%d/n", i);

}

这样编译运行后, 依然是上面的那个结果.

下面对f.c里的f函数做点改变.

改为static void f();

接着编译运行, 发现不能通过.

当时如果把static void f()函数放到test.c文件里, 然后编译运行就一切正确.

用static定义的函数, 只能在一个文件里面对其他函数可见, 在其他文件里就是用了extern也不可见.

接着来分析一下相应程序的汇编代码

---------------------- test.c -------------------------

#include <stdio.h>

extern void f();

int main()

{

    f();

    return 0;

}

static void f()

{

    printf("this is function f/n");

}

(要想看到汇编码, 只要在编译的时候添加编译器选项/FAcs即可.

 vc6里面的设置是: 工程->设置->c/c++-> 分类里选择"文件列表"->列表文件类型选择

 "Assembly, Machine Code, and Source"即可)

------------  汇编码大致如下(仅复制出了关键部分) ------------

;如果将static关键字去掉, 那得到的汇编码里, 在PUBLIC _main前还有个PUBLIC _f

PUBLIC _main

_TEXT SEGMENT

_main PROC NEAR

;{

      push ebp

      mov  ebp, esp

; f();

      call _f

; return 0;

      xor eax, eax

:}

      pop ebp

      ret 0

_main ENDP

_TEXT ENDS

EXTRN  _printf:NEAR

_DATA SEGMENT

$SG338 DB 'this is function f', 0ah, 00h

_DATA ENDS

_TEXT SEGMENT

_f    PROC NEAR

;{

      push ebp

      mov  ebp, esp

; printf("this is function f/n");

      push OFFSET FLAT:$SG338

      call _printf

      all esp, 4

;}

      pop ebp

      ret 0

_f    ENDP

_TEXT ENDS

END

因此关键就在于那个PUBLIC. 

如果你在另外一个文件里面定义static void f(), 那在该文件里没有PUBLIC, 因此EXTERN也没用.

那在同一个文件里的时候, 看上面的汇编码, 它也没有PUBLIC _f, 而且f函数定义在main函数后面, 

那main函数怎么依旧能调用f函数?

对于这点我目前不大确定, 根据我的汇编经验, 汇编码里面应该是可以看见的.

就像你用jum指令可以跳到后面的标号去, 而不用在前面声明标号.

接下来的问题就是, 既然可以看见, 那为什么还要用extern void f();

这就是c语言里面的规定了.

如果不用extern void f() (该语句可以就用void f(); 或 static void f();来代替)

那程序如下:

#include <stdio.h>

int main()

{

    f();      // 当C编译器检查到这里的时候, 会默认f()为一个声明,返回值默认的添加为int

              // 即这条语句在c编译器看来和语句 int f(); 等价.  相当于声明了一个返回int的函数.

              // 因此前面必须加extern void f(); 来声明f, 这样在这里就表示对f函数的调用了.

    return 0;

}

static void f()

{

    printf("this is function f/n");

}

总结下:

1:  extern只能引用外部变量和函数, 外部变量就是定义在所有函数外的变量, 即全局变量.

    因为函数不能嵌套, 所以函数永远就是外部的.

2:  static声明的函数能将该函数作用域限制在一个文件里.   对于变量也是这样的.

3:  全局变量的定义必须在所有函数外面, 定义时只能用常量表达式赋值.

下面对2种情况进行比较.

(1) 

文件 test.c

#include <stdio.h>

int main()

{

    f();

    return 0;

}

void f()

{

    printf("this is function f/n");

}

编译后又一条警告, 一条错误.

test.c(5) : warning C4013: 'f' undefined; assuming extern returning int

test.c(10) : error C2371: 'f' : redefinition; different basic types

(2)

文件 test.c

#include <stdio.h>

int main()

{

    f();

    return 0;

}

文件 f.c

#include <stdio.h>

void f()

{

    printf("this is function f/n");

}

编译后仅有一条警告, 如果运行的话, 程序运行正确.

test.c(5) : warning C4013: 'f' undefined; assuming extern returning int

上面的内容如有错误, 还望指出, 多谢!

晕,  CSDN这里面怎么对TAB识别不出来.    还是说tab不能复制过来.

继续阅读