黑马程序员--05Ctypedef/extern/static

来源:互联网 发布:dnf打团网络冲突 编辑:程序博客网 时间:2024/06/09 16:05

                                       ------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

                                                               

记住一句话:typedef是一个常用的关键字,用来给已经存在的数据类型起别名。


1.基本使用


 1.给变量改名

typedef int Integer;          //int起名为Integer.可以定义为全局的或者局部的

int a = 10;                        //依然可以使用原来的int

Integer b = 10;                //等价于 int b = 10;

已经改名的也可以再改名

typedef Integer MyInteger;     //Integer再改名为MyInteger

MyInteger d = 100;                 //等价于 int d = 100;


2.给指针改名

使用typedef给指针改名可以用来省略星号

typedef char* String;             //String来代表char *

char* s = "abc";                     // char*可以继续使用

String s2 = "ABC";                //就可以这么写了,这里的String就相当于char*


3.给结构体类型改名

a.typedef struct Point { 

float x, y;

} MyPoint;                              // typedef xxx MyPoint;

MyPoint p = {0.5, 1.5};                //等价于 struct Point p = {};

 


b.typedef struct {

float x, y;

} MyPoint;                              // MyPoint代表这整个结构体类型

MyPoint p = {3, 2.5};              //定义一个这种结构体类型的变量


4.给枚举类型起名

typedef enum {SeasonSpring,SeasonSummer,SeasonAutumn,SeasonWinter

} Season;

Season s = SeasonAutumn;

 

5.用于指向函数的指针

有这么一个函数:

int sum (int a, int b) {

return a + b;

}

通常我们是这么定义和使用函数指针的:

int (*p)(int, int);

p = sum;

int c = (*p)(4, 5);         //或者 int c = p(4, 5);

 

使用typedef起别名:

typedef int (*FuncPointer) (int , int);     //这里写了星号,定义变量时就不用写星号了

FuncPointer p;                             //表示p是一个 int (*p) (int, int)类型的函数指针

p = sum;  

int c = (*p)(4, 5);

 

<span style="font-size:12px;">int sum (int a1,int a2){    return a1 +a2;}int main(){    typedef int Myint; // 给基本变量取个新名字    typedef char * String; // 给指针变量取个新名字    typedef struct Student{        int age;        int weight;    }Stu; // 给结构体取个新名字    typedef enum Sex {        Sexman,        Sexwoman,        unknown    }Se; // 给枚举取个新名字    typedef int(*k)(int,int);    k k1 = sum;    int m = (*k1)(4,5); // 给函数取个新名字        Myint i = 10;        String p;    char *s = "jack";    p = s;        Stu p1 = {23,1};        Se s1 = unknown;        NSLog(@"%d-%s-%d,%d-%d-%d",i,p,p1.age,p1.weight,s1,m);        return 0;}</span>

6.补充:typedef和宏定义的区别

typedef char* string1;           //表示给 char*起名为 string1

#define string2 char*;           //表示把 string2替换成 char*

相同点

string1 s = "abc";

string2 ss = "ABC";

区别是:typedef是把类型给换名了,而宏定义只是纯粹的字符串替换

string1 s1, s2;  因为string1是一个类型,所以相当于string1 s1;string1 s2;也就是 char *s1; char *s2;两个都是指针。   

string2 s3, s4;  则相当于   char *s3, s4;  也就相当于  char *s3; char s4;    所以s4并不是一个指针变量,而是一个char变量。


<span style="font-size:12px;">#define String char *int main(){    typedef char * String1;        String a,b; // 区别点在于,一旦编译,这句相当于char *a;    char b;        String a1,b1; //        return 0;}</span>


2.extern与static


1.变量的存储类型

变量可以存储在三个地方:静态内存(静态的变量),运行时的堆栈(动态分配的变量)、硬件寄存器(小而快速,比如单片机里有很多寄存器)

变量根据存储类型不同,可以分为:静态变量,自动变量,寄存器变量


自动变量    auto局部变量

储存位置 存储在程序运行时的堆栈中

变量类型 所有普通的局部变量都是自动变量,它们都默认被auto关键字修饰,auto可以省略。

生命周期在执行到定义变量的代码行时被创建,在当前代码块执行完毕后,会自动被系统销毁,内存被回收。如果这段代码块(比如函数)被重复调用,变量被重复创建和自动销毁。

注:

局部变量会被系统自动销毁,但是如果使用alloc等动态分配给OC对象的内存,需要手动管理内存,系统不会自动释放。


静态变量 全局变量static局部变量

储存位置存储在系统的静态内存中

变量类型所有的全局变量都是静态变量;被static修饰的局部变量也是静态变量。

生命周期      全局变量在整个程序开始运行时就被创建;静态的局部变量在第一次执行到该代码行时被创建,后面不会被重复创建。销毁:静态变量在程序的整个运行期间都存在,在整个程序结束时才被销毁。

注意      static改变了局部变量的生命周期,但不改变它的作用域。

 

# 例子 #int a;                               // a是全局变量,静态变量void test() {int b = 0;               // b是局部变量,自动变量static int c = 0;      // c是局部变量,静态变量。b++; print b;          //多次调用函数,打印结果是什么呢?每次都是1c++; print c;          //多次调用函数,打印结果是什么呢?逐次增加1}int main() {test();test();test();}


bc的作用域相同,销毁时间不同。

ac的作用域不同,销毁时间相同。


2.变量的作用域

局部变量:在代码块{}内部定义的变量

作用域:从定义那一行开始生效,到当前代码块{}结束时失效.

生命周期:从定义那行开始分配存储空间,在当前代码块结束时被销毁,空间被回收.

 

全局变量:{}外面定义的变量

作用域:在这个文件中,从定义变量的那一行开始,到文件结尾.其它文件也可以使用.

生命周期:程序一启动就会分配存储空间,程序退出时才被销毁回收.

全局变量定义时默认值为0.

局部变量定义时默认值任意,必须要初始化.

函数内部使用变量时,优先寻找函数内部定义的变量,如果没有,再在函数外面寻找全局变量.所以,如果函数内部定义了同名的变量,那么调用的就是这个局部变量.

 

int a;     // 全局变量, 定义之后哪里都可以使用voit test() {a = 10;         //可以调用int b = 0;      //局部变量, 只在这个{}中有效}int main() {test();print a;     // a == 10b = 5;        // 不可以调用, b随着test结束被销毁int a = 3;       //局部变量a, 和全局变量是两个变量a = 5;        // 局部变量的值被修改, 全局变量不变.}


注意

自定义的结构体类型/枚举类型的作用域和变量的一致。比如在{}外部定义的结构体类型是全局类型,在它之后的任何位置都可以使用它来定义结构体变量。在{}内部定义的结构体类型,只能在当前{}中用来定义结构体变量,在其它函数中无效。


3.externstatic可以修改函数和变量的取值范围


对函数的作用

函数按照作用域可以分为外部函数和内部函数。

外部函数可以在这个程序的任何文件中调用,内部函数只能在本文件中调用。

不同文件中的外部函数不可以重名,内部函数可以和其它文件的内部函数重名。

如果函数调用在定义之前,或者调用其它文件中的函数,需要声明函数。

 

extern

extern用于定义和声明外部函数,比如

extern void test();              // 完整声明一个外部函数

extern void test() { }          // 完整的定义一个外部函数

函数默认是外部函数,上面的extern可以省略,效果是一样的,这样定义的函数可以在该程序的任何文件中被调用。

static

static用于定义和声明内部函数(静态函数),静态函数只能在本文件中调用。

定义一个内部函数:static void test2() { }

声明一个内部函数:static void test2();

说明

静态函数的声明必须要加上static,因为  void test2(); //等价于extern void test2();

所以必须要声明为  static void test2();        //声明静态函数

虽然静态函数只能在定义的文件中调用,但是其它文件可以间接调用它。如果内部函数所在的文件中有外部函数,那么它的外部函数可以调用这个内部函数,而其它文件中的函数可以调用那个外部函数,从而间接调用了内部函数。


对变量的作用

externextern用来声明一个全局变量,通常都省略不写。

全局变量只能在它定义的位置开始生效,可以被在它定义后的函数和其它文件中的函数访问。如果需要在它定义位置之前的函数访问,有两种方式:

在这个函数前面(外面)声明这个变量,比如extern int a; 这里的extern可以省略

在这个函数里面声明这个变量,比如extern int a;这里的extern不可以省略,因为如果省略了,那int a; 就是定义了一个局部变量了。使用extern那这个函数里的a就是那个全局变量a,不使用extern那就是局部变量的值。

C语言中全局变量是所有文件共享的,不同文件中同名全局变量就是储存在同一个地址的同一个变量。


 static

static修饰局部变量:延长声明周期

static修饰局部变量时,不改变变量的作用域,但是在代码块结束时不销毁变量,延长生命周期至程序结束时才销毁。

static修饰全局变量:限制作用域

全局变量默认是所有文件共享,任何文件都可以修改其它文件的全局变量的值。如果某个全局变量不想被其它文件修改,可以用static修饰为内部的全局变量。static修饰的全局变量只能在当前文件中使用,不可以被其它文件访问。其它文件可以定义同名的内部全局变量,不同文件中同名的内部全局变量不是同一个变量。

  

小结

externstatic作用于函数和变量

函数的定义和声明

外部函数:当前文件中定义的函数允许其它文件访问、调用。函数默认为外部函数,相关的所有源文件不能有同名的外部函数,链接时会报错。

内部函数:当前文件中定义的函数不允许其它文件访问、调用,只能在这个文件内部使用。不同的源文件可以有同名的内部函数。

全局变量

外部全局变量:当前文件中定义的全局变量可以和其它文件共享,所有源文件中同名的变量指向同一个变量

内部全局变量:当前文件中定义的全局变量只能在本文件中使用,不同源文件中同名的变量指向不同的变量

局部变量 

extern用于声明函数中使用的是全局变量

static用于延长局部变量的生命周期至程序结束


0 0
原创粉丝点击