摘要:        
我前面关于stack.c和main.c的讨论。 stack.c这个模块封装了top和stack两个变量,导出了push、 pop、 is_empty三个函数接口,已经设计得比较完善了。但是使用这个模块的每个程序文件都要写三个函数声明也是很麻烦的,假设又有一个foo.c也使用这个模块, main.c和    
阅读全文
 
 
        
        posted @ 2018-04-08 08:53
刘-皇叔
阅读(193)
推荐(0)
        
            
        
        
摘要:        
在上一节我们把两个程序文件放在一起编译链接,main.c用到的函数push、 pop和is_empty由stack.c提供,其实有一点小问题,我们用-Wall选项编译main.c可以看到: 由于编译器在处理函数调用代码时没有找到函数原型,只好根据函数调用代码做隐式声明,把这三个函数声明为: 为什么编    
阅读全文
 
 
        
        posted @ 2018-04-08 08:46
刘-皇叔
阅读(588)
推荐(2)
        
            
        
        
摘要:        
考虑下面几个程序段: 编译时可以一步编译 : 也可以多步编译: 用nm命令查看目标文件的符号表,会发现main.o中有未定义的符号push、 pop、 is_empty、 putchar,前三个符号在stack.o中实现了,链接生成可执行文件main时可以做符号解析,而putchar是libc的库函    
阅读全文
 
 
        
        posted @ 2018-04-08 08:28
刘-皇叔
阅读(241)
推荐(0)
        
            
        
        
摘要:        
一层指针的参数 如果函数接口有指针参数,既可以把指针所指向的数据传给函数使用(称为传入参数),也可以由函数填充指针所指的内存空间,传回给调用者使用(称为传出参数)。有些函数的指针参数同时担当了这两种角色,既是传入参数又是传出参数,这称为Value-result参数。 传入参数 void func(c    
阅读全文
 
 
        
        posted @ 2018-04-08 00:09
刘-皇叔
阅读(718)
推荐(0)
        
 
		
    
        
        
摘要:        
不完全类型是暂时没有完全定义好的类型,编译器不知道这种类型该占几个字节的存储空间,例如: 具有不完全类型的变量可以通过多次声明组合成一个完全类型,比如数组str声明两次: 当编译器碰到第一个声明时,认为str是一个不完全类型,碰到第二个声明时str就组合成完全类型了,如果编译器处理到程序文件的末尾仍    
阅读全文
 
 
        
        posted @ 2018-04-07 23:49
刘-皇叔
阅读(389)
推荐(0)
        
            
        
        
摘要:        
指向数组的指针 以下定义一个指向数组的指针,该数组有10个int元素: []比*有更高的优先级,如果a先和*结合则表示a是一个指针,如果a先和[]结合则表示a是一个数组。 int *a[10];这个定义可以拆成两句: t代表int *类型, a则是由这种类型的元素组成的数组。 int (*a)[10    
阅读全文
 
 
        
        posted @ 2018-04-07 23:41
刘-皇叔
阅读(473)
推荐(0)
        
            
        
        
摘要:        
要通过指针p访问结构体成员可以写成(*p).c和(*p).num,为了书写方便, C语言提供了->运算符,也可以写成p->c和p->num。    
阅读全文
 
 
        
        posted @ 2018-04-07 23:28
刘-皇叔
阅读(183)
推荐(0)
        
            
        
        
摘要:        
const限定符和指针结合起来常见的情况有以下几种。: 这两种写法是一样的, a是一个指向const int型的指针, a所指向的内存单元不可改写,所以(*a)++是不允许的,但a可以改写,所以a++是允许的。 a是一个指向int型的const指针, *a是可以改写的,但a不允许改写。 a是一个指向    
阅读全文
 
 
        
        posted @ 2018-04-07 23:27
刘-皇叔
阅读(293)
推荐(0)
        
            
        
        
摘要:        
(1)首先指针pa指向a[0]的地址,注意后缀运算符的优先级高于单目运算符,所以是取a[0]的地址,而不是取a的地址。然后pa++让pa指向下一个元素(也就是a[1]),由于pa是int *指针,一个int型元素占4个字节,所以pa++使pa所指向的地址加4,注意不是加1。 (2)a[2]和pa[2    
阅读全文
 
 
        
        posted @ 2018-04-07 23:19
刘-皇叔
阅读(733)
推荐(0)
        
            
        
        
摘要:        
我们知道,调用函数的传参过程相当于用实参定义并初始化形参, swap(&i, &j)这个调用相当于: 所以px和py分别指向main函数的局部变量i和j,在swap函数中读写*px和*py其实是读写main函数的i和j。尽管在swap函数的作用域中访问不到i和j这两个变量名,却可以通过地址访问它们,    
阅读全文
 
 
        
        posted @ 2018-04-07 23:11
刘-皇叔
阅读(1405)
推荐(0)
        
            
        
        
摘要:        
野指针和空指针 在堆栈上分配的变量初始值是不确定的,也就是说指针p所指向的内存地址是不确定的,后面用*p访问不确定的地址就会导致不确定的后果,如果导致段错误还比较容易改正,如果意外改写了数据而导致随后的运行中出错,就很难找到错误原因了。像这种指向不确定地址的指针称为“野指针”(Unbound Poi    
阅读全文
 
 
        
        posted @ 2018-04-07 23:05
刘-皇叔
阅读(401)
推荐(0)
        
            
        
        
摘要:        
1、三连符替换成相应的单字符(例如用??=表示#字符。)。 2、把用\字符续行的多行代码接成一行。例如: 经过这个预处理步骤之后接成一行: 这种续行的写法要求\后面紧跟换行,中间不能有其它空白字符。 3、把注释(不管是单行注释还是多行注释)都替换成一个空格。 4、经过以上两步之后去掉了一些换行,有的    
阅读全文
 
 
        
        posted @ 2018-04-07 22:52
刘-皇叔
阅读(981)
推荐(0)
        
            
        
        
摘要:        
关键字就是已被C语言本身使用,不能作为其它标识符由ANSI标准定义的C语言关键字共32个: 根据关键字的作用,可以将关键字分为数据类型关键字和流程控制关键字两大类。 (1) 数据类型关键字 1) 基本数据类型(5个) void;char;int;float;double 2) 类型修饰关键字(4个)    
阅读全文
 
 
        
        posted @ 2018-04-07 22:37
刘-皇叔
阅读(246)
推荐(0)
        
            
        
        
摘要:        
扩展的行内汇编 在扩展的行内汇编中,可以将 C 语言表达式指定为汇编指令的操作数,而且不用去管如何将 C 语言表达式的值读入寄存器,以及如何将计算结果写回 C 变量,你只要告诉程序中 C 语言表达式与汇编指令操作数之间的对应关系即可,GCC 会自动插入代码完成必要的操作。 使用内嵌汇编,要先编写汇编    
阅读全文
 
 
        
        posted @ 2018-04-07 22:33
刘-皇叔
阅读(1659)
推荐(0)
        
            
        
        
摘要:        
Linux 操作系统内核代码绝大部分使用 C 语言编写,只有一小部分使用汇编语言编写,例如与特定体系结构相关的代码和对性能影响很大的代码。 GCC 提供了内嵌汇编的功能,可以在 C 代码中直接内嵌汇编语言语句,大大方便了程序设计。 基本行内汇编 基本行内汇编很容易理解,一般是按照下面的格式: 同时“    
阅读全文
 
 
        
        posted @ 2018-04-07 22:31
刘-皇叔
阅读(227)
推荐(0)
        
            
        
        
摘要:        
结构体 main函数中几条语句的反汇编结果如下: 从访问结构体成员的指令可以看出,结构体的四个成员在栈上是这样排列的: 虽然栈是从高地址向低地址增长的,但结构体成员也是从低地址向高地址排列的,这一点和数组类似。但有一点和数组不同,结构体的各成员并不是一个紧挨一个排列的,中间有空隙,称为填充(Padd    
阅读全文
 
 
        
        posted @ 2018-04-07 22:29
刘-皇叔
阅读(440)
推荐(0)
        
            
        
        
摘要:        
我们在全局作用域和main函数的局部作用域各定义了一些变量,并且引入一些新的关键字const、 static、 register来修饰变量,那么这些变量的存储空间是怎么分配的呢?我们编译之后用readelf命令看它的符号表,了解各变量的地址分布。注意在下面的清单中我把符号表按地址从低到高的顺序重新排    
阅读全文
 
 
        
        posted @ 2018-04-07 22:19
刘-皇叔
阅读(262)
推荐(0)
        
            
        
        
摘要:        
存储类修饰符 存储类修饰符(Storage Class Specifier)有以下几种关键字,可以修饰变量或函数声明: (1)static,用它修饰的变量的存储空间是静态分配的,用它修饰的文件作用域的变量或函数具有Internal Linkage。 (2)auto,用它修饰的变量在函数调用时自动在栈    
阅读全文
 
 
        
        posted @ 2018-04-07 22:14
刘-皇叔
阅读(287)
推荐(0)
        
            
        
        
摘要:        
作用域 作用域是程序中定义的变量所存在的区域,超过该区域变量就不能被访问。编译器可以确认4种不同类型的作用域:文件作用域,函数作用域,代码块作用域,原型作用域。 代码块作用域 位于一对花括号之间的语句称为语句块,任何在代码块的开始位置声明的标识符都具有代码块作用域,表示它们可以被这个代码块中的所有语    
阅读全文
 
 
        
        posted @ 2018-04-07 22:07
刘-皇叔
阅读(755)
推荐(0)
        
            
        
        
摘要:        
汇编程序的入口是_start,而C程序的入口是main函数。 汇编和链接步骤是: 以前我们常用gcc main.c -o main命令编译一个程序,其实也可以分三步做,第一步生成汇编代码,第二步生成目标文件,第三步生成可执行文件: -S选项生成汇编代码, -c选项生成目标文件,此外-E选项只做预处理    
阅读全文
 
 
        
        posted @ 2018-04-07 16:03
刘-皇叔
阅读(1398)
推荐(0)