C语言笔记

发布 2021-05-12 01:01:28 阅读 1213

typedef声明,简称typedef,为现有类型创建一个新的名字,或称为类型别名,在结构体定义,还有一些数组等地方都大量的用到。

typedef使用最多的地方是创建易于记忆的类型名,用它来归档程序员的意图。类型出现在所声明的变量名字中,位于“typedef”关键字右边。例如:

此声明定义了一个int的同义字,名字为size。注意typedef并不创建新的类型。它仅仅为现有类型添加一个同义字。你可以在任何需要int的上下文中使用size:

typedef 还可以掩饰复合类型,如指针和数组。

例如,你不用像下面这样重复定义有 81 个字符元素的数组:

定义一个 typedef,每当要用到相同类型和大小的数组时,可以这样:

此时line类型即代表了具有81个元素的字符数组,使用方法如下:

同样,可以像下面这样隐藏指针语法:

这里将带我们到达第一个 typedef 陷阱。标准函数 strcmp()有两个‘ const char *'类型的参数。因此,它可能会误导人们像下面这样声明 mystrcmp():

用gnu的gcc和g++编译器,是会出现警告的,按照顺序,‘const pstr'被解释为‘char* const‘(一个指向char的指针常量),两者表达的并非同一意思(详见c++ primer 第四版 p112)。

char * const cp : 定义一个指向字符的指针常数,即const指针,常指针。

const char* p : 定义一个指向字符常数的指针,即常量指针。

char const* p : 等同于const char* p[2]。

为了得到正确的类型,应当如下声明:

3. typedef & #define的问题。

有下面两种定义pstr数据类型的方法,两者有什么不同?哪一种更好一点?

答案与分析:

通常讲,typedef要比#define要好,特别是在有指针的场合。请看例子:

在上述的变量定义中,s1、s2、s3都被定义为char *,而s4则定义成了char,不是我们所预期的指针变量,根本原因就在于#define只是简单的字符串替换而typedef则是为一个类型起新名字。

上例中define语句必须写成 pstr2 s3, *s4; 这这样才能正常执行。

#define用法例子:

以下程序的输出结果是: 36。

因为如此原因,在许多c语言编程规范中提到使用#define定义时,如果定义中包含表达式,必须使用括号,则上述定义应该如下定义才对:

#define f(x) (x)*(x))

当然,如果你使用typedef就没有这样的问题。

4. typedef & #define的另一例。

下面的**中编译器会报一个错误,你知道是哪个语句错了吗?

答案与分析:

是p2++出错了。这个问题再一次提醒我们:typedef和#define不同,它不是简单的文本替换。

上述**中const pstr p2并不等于const char * p2。const pstr p2和const long x本质上没有区别,都是对变量进行只读限制,只不过此处变量p2的数据类型是我们自己定义的而不是系统固有类型而已。因此,const pstr p2的含义是:

限定数据类型为char *的变量p2为只读,因此p2++错误。

#define与typedef引申谈。

#define宏定义有一个特别的长处:可以使用 #ifdef ,#ifndef等来进行逻辑判断,还可以使用#undef来取消定义。

2) typedef也有一个特别的长处:它符合范围规则,使用typedef定义的变量类型其作用范围限制在所定义的函数或者文件内(取决于此变量定义的位置),而宏定义则没有这种特性。

5. typedef & 复杂的变量声明。

在编程实践中,尤其是看别人**的时候,常常会遇到比较复杂的变量声明,使用typedef作简化自有其价值,比如:

下面是三个变量的声明,我想使用typdef分别给它们定义一个别名,请问该如何做?

1:int *(a[5])(int, char*);

2:void (*b[10]) void (*

3. doube(*)pa)[9];

答案与分析:

对复杂变量建立一个类型别名的方法很简单,你只要在传统的变量声明表达式里用类型名替代变量名,然后把关键字typedef加在该语句的开头就行了。

1:int *(a[5])(int, char*);

/pfun是我们建的一个类型别名。

typedef int *(pfun)(int, char*);

/使用定义的新类型来声明对象,等价于int* (a[5])(int, char*);

pfun a[5];

2:void (*b[10]) void (*

/首先为上面表达式蓝色部分声明一个新类型。

typedef void (*pfunparam)()

/整体声明一个新类型。

typedef void (*pfun)(pfunparam);

/使用定义的新类型来声明对象,等价于void (*b[10]) void (*

pfun b[10];

3. doube(*)pa)[9];

/首先为上面表达式蓝色部分声明一个新类型。

typedef double(*pfun)()

/整体声明一个新类型。

typedef pfun (*pfunparam)[9];/使用定义的新类型来声明对象,等价于doube(*)pa)[9];

pfunparam pa;

xtern “c”

含义。1) 被extern限定的函数或变量是extern类型的:

修饰变量的声明。举例来说,如果文件需要引用中变量int v,就可以在中声明externint v,然后就可以引用变量v。这里需要注意的是,被引用的变量v的链接属性必须是外链接(external)的,也就是说要引用到v,不只是取决于在中声明externint v,还取决于变量v本身是能够被引用到的。

这涉及到c语言的另外一个话题--变量的作用域。能够被其他模块以extern修饰符引用到的变量通常是全局变量。还有很重要的一点是,externint v可以放在中的任何地方,比如你可以在中的函数fun定义的开头处声明extern int v,然后就可以引用到变量v了,只不过这样只能在函数fun作用域中引用v罢了,这还是变量作用域的问题。

对于这一点来说,很多人使用的时候都心存顾虑。好像extern声明只能用于文件作用域似的。

修饰函数声明。从本质上来讲,变量和函数没有区别。函数名是指向函数二进制块开头处的指针。

如果文件需要引用中的函数,比如在中原型是int fun(int mu),那么就可以在中声明extern int fun(int mu),然后就能使用fun来做任何事情。就像变量的声明一样,externint fun(int mu)可以放在中任何地方,而不一定非要放在的文件作用域的范围中。对其他模块中函数的引用,最常用的方法是包含这些函数声明的头文件。

使用extern和包含头文件来引用函数有什么区别呢?extern的引用方式比包含头文件要简洁得多!extern的使用方法是直截了当的,想引用哪个函数就用extern声明哪个函数。

这大概是kiss原则的一种体现吧!这样做的一个明显的好处是,会加速程序的编译(确切的说是预处理)的过程,节省时间。在大型c程序编译过程中,这种差异是非常明显的。

2) 被extern "c"修饰的变量和函数是按照c语言方式编译和连接的;

未加extern“c”声明时的编译方式。

首先看看c++中对类似c的函数是怎样编译的。

作为一种面向对象的语言,c++支持函数重载,而过程式语言c则不支持。函数被c++编译后在符号库中的名字与c语言的不同。例如,假设某个函数的原型为:

void foo( int x, int y );

该函数被c编译器编译后在符号库中的名字为_foo,而c++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为“mangled name”)。foo_int_int这样的名字包含了函数名、函数参数数量及类型信息,c++就是靠这种机制来实现函数重载的。例如,在c++中,函数void foo( int x, int y )与void foo( int x, float y )编译生成的符号是不相同的,后者为_foo_int_float。

同样地,c++中的变量除支持局部变量外,还支持类成员变量和全局变量。用户所编写程序的类成员变量可能与全局变量同名,我们以"."来区分。

而本质上,编译器在进行编译时,与函数的处理相似,也为类中的变量取了一个独一无二的名字,这个名字与用户程序中同名的全局变量名字不同。

C语言笔记

第一课时。c语言标准格式。include vidomain 以 开头的语句称为预处理指令。include语句不是必须的,但是如果一旦有该语句就必须把它放在文件开始处是standared input output header的缩写standared 标准input 输入output 输出header...

C语言笔记

c语言算法和数据类型。整型。基本类型 字符型注释 基本类型的特点是其不可实型 单精度型以再分解为其他类型双精度型数组型。数据结构 构造型 结构体型共用体型指针型空类型。一 常量。define 语句不以分号结尾,它可以放在源 的任何位置。不过在定义常量时,只有在它定义后的源 中才有效。是一个修饰符,在...

c语言笔记

1.if中别忘了 而不是 2.写完程序别忘了检查前后大括号 小括号是否完全照应。3.遇到几分之几的分数可以方程两边同时乘以一个数来消去分母。4.写指针题时看准指针对应的是行还是列。例 int a 4 3 int p a 0 列指针。int ptr 3 a 行指针。5.考虑好哪些量会随着循环不断改变。...