《C专家编程》读书笔记(一)

更新时间:2023-10-23 13:35:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

《C专家编程》读书笔记(一)

By:LShang

Blog:http://www.cnblogs.com/LShang

C 语言的发展

1965-7(BCPL)->1969(B)->1971(New B)->1972-3(早期的C)->1976-9(K&C)->1983-9

(ANSI C)->

C 的许多特性是为了方便编译器设计者而建立的

? 数组下标从0开始(定义数组a[100]的合法范围是a[0] ~ a[99])

? 基本数据类型直接与底层硬件对应

? auto关键字只对创建符号表入口的编译器设计者有意义(进入程序块时自动分配内

存)

? 表达式中的数组名可以看作是指针(并非永远如此)

? float会被自动扩展为double(仅在最初如此,ANSI C不再如此) ? 不允许嵌套函数(函数内部不允许包含另一个函数的定义)

? register关键字(可以提供程序中的热门变量,使之将其存放到寄存器中。)

关于register关键字,书中说

“这个设计可以说是一个失误,如果让编译器在使用各个变量时自动处理寄存器的分配工作,显然比一经声明就把这类变量在生命期内始终保留在寄存器里要好。使用register关键字,

简化了编译器,却把包袱丢给了程序员。”

C 编译器不曾实现的一些功能必须通过其他途径实现:

标准 I/O 库和 C 预处理器

最早的可移植 I/O 库出现在1972年,由 Mike Lesk 编写

C 预处理器主要实现三个功能

? 字符串替换 ? 头文件包含

? 通用代码模板的扩展(宏) 宏的实际参数只按照原样输出。

在宏的扩展中,空格会对扩展的结果造成很大影响。

#define a(y) a_expanded(y)

a(x) //被扩展为 a_expanded(x);

//而

#define a (y) a_expanded(y)

//则被扩展为 (y) a_expanded (y)(x);

复制代码 书中建议:

? 宏最好只用于命名常量,并为一些适当的结构提供简捷的记法。

? 宏名应该大写,这样便容易与函数名区分

?? 千万不要使用 C 预处理器来修改语言的基础结构,因为这样 C 就不再是 C

K&R C 和 ANSI C

1978年,《The C Program Language》一书出版,其作者 Brian Kernighan 和 Dennis Ritchie 名

声大噪。这个版本的 C 被称为 K&R C

1983年,美国国家标准化组织(ANSI)成立了 C 语言工作小组,开始了 C 语言的标准化

工作

1989年12月,ANSI委员会接受了 C 语言标准草案,随后国际标准化组织 ISO 也接纳了

ANSI C 标准(C 89标准)

1990年初,ANSI 重新采纳了 ISO C(删除掉了Rationale一节),所以原则上说日常所说的

标准 C 应是 ISO C 而不是 ANSI C

K&R C 和 ANSI C 的区别

?? 函数原型的增加 ?? 关键字的增加 ?? 安静的改变 ?? 其他区别

原型是函数声明的扩展,这样不仅函数名和返回类型已知,所有形参类型也是已知的

参数传递的过程类似于赋值

每个实参都应该具有自己的类型,这样它的值就可以赋值给与它所对应的形参类型的对象

(该对象的类型不能含有限定符) 参数传递时的相容与不相容

char *cp; constchar *ccp; ccp = cp; //可以相容 复制代码

char * 是一个指向没有限定符的 char 型指针

const char * 是一个指向有 const 限定符的 char 型指针

char 类型与 char 类型可以相容,左操作数(形参)具有右操作数(实参)所指向类型的限

定符(无限定符),再加上自身的限定符(const)。

char *cp; constchar *ccp; cp = ccp; //不可以相容 复制代码

char * 是一个指向没有限定符的 char 型指针

const char * 是一个指向有 const 限定符的 char 型指针

char 类型与 char 类型可以相容,左操作数(形参)不具有右操作数(实参)所指向类型的

限定符(const)

测试代码 #include

int main()

{

char *cp = {\}; constchar *ccp = cp;

printf(\,ccp);

return0; } 复制代码

--------------------Configuration: Test - Win32 Debug--------------------

Compiling... Test.c

Test.obj - 0 error(s), 0 warning(s)

#include

int main()

{

constchar *cp = {\};

char *ccp = cp; printf(\,ccp);

return0; } 复制代码

--------------------Configuration: Test - Win32 Debug--------------------

Compiling... Test.c

C:\\Code\\Test\\Test.c(5) : warning C4090: 'initializing' : different 'const' qualifiers

Test.obj - 0 error(s), 1 warning(s)

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////

借用书中代码 foo(constchar **p) {} main(int argc,char **argv)

{

foo(argv);

} 复制代码

根据 ANSI C 标准,此代码中的形参和实参是不相容的 const char **p 指向一个没有限定符的 const char * 型指针

char **argv 指向一个没有限定符的 char * 型指针

虽然形参具有实参所指向类型的限定符(无),但是由于形参和实参所指向的类型不一样,

所以它们不相容

const char * 类型与 char * 类型可以相容,但相容性无法传递,所以即使const char * 类型与 char * 类型可以相容也不代表const char ** 类型和 char ** 类型可以相容,所以虽然

const char ** 类型和 char ** 类型都没有限定符,但是它们之间不能进行赋值

以上内容均根据理论推出,书中提到这种赋值方式在 C ++编译器中是合法的,所以无法在

VC 环境下测试,TC 2.0环境貌似也没有警告。。。

const 限定符

关键字 const 并不能将一个变量变成一个常量

在一个符号前加上 const 限定符只是表示这个符号不能被赋值,但它并不能防止通过其他

方法来修改这个值(如指针)

constint n;

// 带有限定符(const)的 int 型变量,n 不可改变

constint *n;

// 指向一个带有限定符(const)的 int 的指针,*n 不可改变

constint **n;

// 指向一个带有限定符(const)的 int 的指针的指针,**n 不可改变

... ... 复制代码

但可以通过其他方式来间接改变带有 const 限定符的变量的值

#include

int main()

{

constint n = 0; int *pn = &n;

printf(\,n);

*pn = 1;

printf(\,n);

return0; } 复制代码

虽然在编译时会产生一条警告信息

--------------------Configuration: Test - Win32 Debug--------------------

Compiling... Test.c

C:\\Code\\Test\\Test.c(6) : warning C4090: 'initializing' : different 'const' qualifiers

Test.obj - 0 error(s), 1 warning(s) 但是程序可以正常链接和运行

而且也满足了间接修改一个带有 const 限定符的变量的值的要求

n = 0 n = 1

Press any key to continue

算术转换的改变

K&R C 采用无符号保留(unsigned preserving)原则,就是当一个无符号类型与 int 或更小

的整型混合使用时,结果类型是无符号类型

ANSI C 采用值保留(value preserving)原则,就是把几个整型操作数混合使用时,结果类

型有可能是符号数,也可能是无符号数,取决于操作数的类型的相对大小

采用通俗语言,ANSI C 标准所表示的意思大致如下:

当执行算术运算时,操作数的类型如果不同,就会发生转换。数据类型一般朝着浮点精度更高、长度更长的方向转换,整型数如果转换为 signed 不会丢失信息,就转换为 signed,

否则转换为 unsigned。 对无符号类型的建议

? 尽量不要再你的代码中使用无符号类型,以免增加不必要的复杂性。

? 尽量使用像 int 那样的有符号类型,这样在涉及升级混合类型的复杂细节时,不必

担心边界情况。

? 只有在使用位段和二进制掩码时,才可以用无符号数。应该在表达式中使用强制类型转换,是操作数均为有符号数或无符号数,这样就不必有编译器来选择结果类型。

技术是亘古不变的追求

本文来源:https://www.bwwdw.com/article/zfuf.html

Top