文章分类 - C语言基础
发表于 2018-04-08 16:04阅读:386评论:0推荐:0
摘要:ELF文件格式是一个开放标准,各种UNIX系统的可执行文件都采用ELF格式,它有三种不同的类型: 可重定位的目标文件(Relocatable,或者Object File) 可执行文件(Executable) 共享库(Shared Object,或者Shared Library) ELF格式提供了两种
阅读全文 »
发表于 2018-04-08 15:53阅读:1221评论:0推荐:0
摘要:虚拟内存管理示例 我们知道操作系统利用体系结构提供的VA到PA的转换机制实现虚拟内存管理。有了共享库的基础知识之后,现在我们可以进一步理解虚拟内存管理了。首先分析一个例子: 用ps命令查看当前终端下的进程,得知bash进程的id是29977,然后用cat /proc/29977/maps命令查看它的
阅读全文 »
发表于 2018-04-08 15:16阅读:719评论:0推荐:0
摘要:动态函数库同共享函数库是一个东西(在linux上叫共享对象库, 文件后缀是.so ,windows上叫动态加载函数库,文件后缀是.dll)。 Linux中命名系统中共享库的规则: 共享函数库中的函数是在当一个可执行程序在启动的时候被加载。如果一个共享函数库正常安装,所有的程序在重新运行的时候都可以自
阅读全文 »
发表于 2018-04-08 09:05阅读:216评论:0推荐:0
摘要:创建静态库 有时候需要把一组代码编译成一个库,这个库在很多项目中都要用到,例如libc就是这样一个库,我们在不同的程序中都会用到libc中的库函数(例如printf),也会用到libc中的变量。 我们把stack.c拆成四个程序文件: 这些文件的目录结构是: 我们把stack.c、 push.c、
阅读全文 »
发表于 2018-04-08 08:53阅读:181评论:0推荐:0
摘要:我前面关于stack.c和main.c的讨论。 stack.c这个模块封装了top和stack两个变量,导出了push、 pop、 is_empty三个函数接口,已经设计得比较完善了。但是使用这个模块的每个程序文件都要写三个函数声明也是很麻烦的,假设又有一个foo.c也使用这个模块, main.c和
阅读全文 »
发表于 2018-04-08 08:46阅读:572评论:0推荐:2
摘要:在上一节我们把两个程序文件放在一起编译链接,main.c用到的函数push、 pop和is_empty由stack.c提供,其实有一点小问题,我们用-Wall选项编译main.c可以看到: 由于编译器在处理函数调用代码时没有找到函数原型,只好根据函数调用代码做隐式声明,把这三个函数声明为: 为什么编
阅读全文 »
发表于 2018-04-08 08:28阅读:235评论:0推荐:0
摘要:考虑下面几个程序段: 编译时可以一步编译 : 也可以多步编译: 用nm命令查看目标文件的符号表,会发现main.o中有未定义的符号push、 pop、 is_empty、 putchar,前三个符号在stack.o中实现了,链接生成可执行文件main时可以做符号解析,而putchar是libc的库函
阅读全文 »
发表于 2018-04-08 00:09阅读:709评论:0推荐:0
摘要:一层指针的参数 如果函数接口有指针参数,既可以把指针所指向的数据传给函数使用(称为传入参数),也可以由函数填充指针所指的内存空间,传回给调用者使用(称为传出参数)。有些函数的指针参数同时担当了这两种角色,既是传入参数又是传出参数,这称为Value-result参数。 传入参数 void func(c
阅读全文 »
发表于 2018-04-07 23:49阅读:374评论:0推荐:0
摘要:不完全类型是暂时没有完全定义好的类型,编译器不知道这种类型该占几个字节的存储空间,例如: 具有不完全类型的变量可以通过多次声明组合成一个完全类型,比如数组str声明两次: 当编译器碰到第一个声明时,认为str是一个不完全类型,碰到第二个声明时str就组合成完全类型了,如果编译器处理到程序文件的末尾仍
阅读全文 »
发表于 2018-04-07 23:41阅读:465评论:0推荐:0
摘要:指向数组的指针 以下定义一个指向数组的指针,该数组有10个int元素: []比*有更高的优先级,如果a先和*结合则表示a是一个指针,如果a先和[]结合则表示a是一个数组。 int *a[10];这个定义可以拆成两句: t代表int *类型, a则是由这种类型的元素组成的数组。 int (*a)[10
阅读全文 »
发表于 2018-04-07 23:28阅读:174评论:0推荐:0
摘要:要通过指针p访问结构体成员可以写成(*p).c和(*p).num,为了书写方便, C语言提供了->运算符,也可以写成p->c和p->num。
阅读全文 »
发表于 2018-04-07 23:27阅读:283评论:0推荐:0
摘要:const限定符和指针结合起来常见的情况有以下几种。: 这两种写法是一样的, a是一个指向const int型的指针, a所指向的内存单元不可改写,所以(*a)++是不允许的,但a可以改写,所以a++是允许的。 a是一个指向int型的const指针, *a是可以改写的,但a不允许改写。 a是一个指向
阅读全文 »
发表于 2018-04-07 23:19阅读:725评论:0推荐: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
阅读全文 »
发表于 2018-04-07 23:11阅读:1398评论:0推荐:0
摘要:我们知道,调用函数的传参过程相当于用实参定义并初始化形参, swap(&i, &j)这个调用相当于: 所以px和py分别指向main函数的局部变量i和j,在swap函数中读写*px和*py其实是读写main函数的i和j。尽管在swap函数的作用域中访问不到i和j这两个变量名,却可以通过地址访问它们,
阅读全文 »
发表于 2018-04-07 23:05阅读:395评论:0推荐:0
摘要:野指针和空指针 在堆栈上分配的变量初始值是不确定的,也就是说指针p所指向的内存地址是不确定的,后面用*p访问不确定的地址就会导致不确定的后果,如果导致段错误还比较容易改正,如果意外改写了数据而导致随后的运行中出错,就很难找到错误原因了。像这种指向不确定地址的指针称为“野指针”(Unbound Poi
阅读全文 »
发表于 2018-04-07 22:52阅读:918评论:0推荐:0
摘要:1、三连符替换成相应的单字符(例如用??=表示#字符。)。 2、把用\字符续行的多行代码接成一行。例如: 经过这个预处理步骤之后接成一行: 这种续行的写法要求\后面紧跟换行,中间不能有其它空白字符。 3、把注释(不管是单行注释还是多行注释)都替换成一个空格。 4、经过以上两步之后去掉了一些换行,有的
阅读全文 »
发表于 2018-04-07 22:37阅读:237评论:0推荐:0
摘要:关键字就是已被C语言本身使用,不能作为其它标识符由ANSI标准定义的C语言关键字共32个: 根据关键字的作用,可以将关键字分为数据类型关键字和流程控制关键字两大类。 (1) 数据类型关键字 1) 基本数据类型(5个) void;char;int;float;double 2) 类型修饰关键字(4个)
阅读全文 »
发表于 2018-04-07 22:33阅读:1635评论:0推荐:0
摘要:扩展的行内汇编 在扩展的行内汇编中,可以将 C 语言表达式指定为汇编指令的操作数,而且不用去管如何将 C 语言表达式的值读入寄存器,以及如何将计算结果写回 C 变量,你只要告诉程序中 C 语言表达式与汇编指令操作数之间的对应关系即可,GCC 会自动插入代码完成必要的操作。 使用内嵌汇编,要先编写汇编
阅读全文 »
发表于 2018-04-07 22:31阅读:214评论:0推荐:0
摘要:Linux 操作系统内核代码绝大部分使用 C 语言编写,只有一小部分使用汇编语言编写,例如与特定体系结构相关的代码和对性能影响很大的代码。 GCC 提供了内嵌汇编的功能,可以在 C 代码中直接内嵌汇编语言语句,大大方便了程序设计。 基本行内汇编 基本行内汇编很容易理解,一般是按照下面的格式: 同时“
阅读全文 »
发表于 2018-04-07 22:29阅读:424评论:0推荐:0
摘要:结构体 main函数中几条语句的反汇编结果如下: 从访问结构体成员的指令可以看出,结构体的四个成员在栈上是这样排列的: 虽然栈是从高地址向低地址增长的,但结构体成员也是从低地址向高地址排列的,这一点和数组类似。但有一点和数组不同,结构体的各成员并不是一个紧挨一个排列的,中间有空隙,称为填充(Padd
阅读全文 »