Linux C语言结构体
前面学习了c语言的基本语法特性,本节进行更深入的学习。
预处理程序。 编译指令: 预处理, 宏定义,
建立自己的数据类型:结构体,联合体,动态数据结构
c语言表达式工具 逻辑运算符:
& | ^ ~ << >>
函数的递归调用方法
什么是预处理
vim helloworld.c1
helloworld.c:
#include int main()
{ printf("hello,world!\n"); return 0;
}1234567
编译的目的:
从c语言
.c
源文件变成可执行文件
gcc helloworld.c -o helloworld.out./helloworld.out12
编译的四个步骤:
.c
文件->.i
文件->.s
文件->.o
文件->可执行文件(可运行)
下面我们来查看预处理中要做的事情:
gcc -o helloworld.i helloworld.c -E1
-E
表示只让gcc执行预处理。
// 查看helloworld.i文件cat helloworld.i12
vim跳到整个文档底部,命令: :$
可以看到代码的底端是我们的main函数
对比一下.i
文件和.c
文件的区别
首先:它们都是c的语法。其次.c文件main函数上面是
#include
而.i
文件中这行代码不见了,变成了上面这些东西。
所以预处理所做的第一件事情就是展开头文件
将#include
中stdio.h
展开,将未注释的内容直接写入.i文件。
在预处理步骤中,除了展开头文件,还要进行宏替换。
宏是什么
c语言常量分为直接常量和符号常量:
#define 标识符 常量值 (注意:没有分号)1
helloMacro.c源代码:
#include #define R 10int main()
{ int a =R; printf("a=%d\n"); printf("hello,world!\n"); return 0;
}12345678910
gcc -o helloMacro.i helloMacro.c -E1
预处理过之后的代码
# 4 "helloworld.c"int main()
{ int a =10; printf("a=%d\n"); printf("hello,world!\n"); return 0;
}12345678
可以看到10是直接当做一个字符串来替换原本的宏定义R。
宏的本质是发生在预处理阶段单纯的字符串替换(宏替换), 在预处理阶段,宏不考虑语法;
示例代码2:
vim helloMacro2.c
#include #define R 10#define M int main(M){ printf("hello,world!\n"); return 0;
}12345678
gcc helloMacro2.c -o helloMacro2.out./helloMacro2.out12
预处理是没有问题的,可以成功的编译执行。宏不考虑C语言的语法。它很单纯,字符串替换。
宏用于大量反复使用的常量、数组buffer的大小,为了便于修改定义成宏。
通常定义数组我们这样写:
int a[10];int b[10];12
定义两个相同大小的数组,这里我们就可以改为下面代码。
#define R 10int a[R];int b[R];123
一次修改,可以修改两份。
宏也是可以传递参数的,可以做一些函数可以做的事情
宏函数
vim helloMacroFunction.c
源代码:
#include #define R 10#define M int main(#define N(n) n*10M){ int a = R; int b = N(a); printf("b = %d\n",b); printf("a =%d\n",a); printf("hello,world!\n"); return 0;
}123456789101112131415
gcc helloMacroFunction.c -o helloMacroFunction.out./helloMacroFunction.out12
这里的处理过程: 首先将参数a替换到上面的宏中,上面就变成了
N(a) a*10
,之后再用a*10
替换下面的N(a)
int b = N(a); //变成了 int b =a*10;1
gcc -o helloMacroFunction.i helloMacroFunction.c -E1
预处理之后:
# 8 "hello.c"int main(){ int a = 10; int b =a*10; printf("b = %d\n",b); printf("a =%d\n",a); printf("hello,world!\n"); return 0;
}123456789
先不考虑宏实现,先来写一个正常的求和函数。
vim helloAdd.c1
#include #define R 20#define M int main(#define N(n) n*10int add(int a,int b){ return a b;
}M){ int a = R; printf("a =%d\n",a); printf("hello,world!\n"); int b =N(a); printf("b = %d\n",b); int c =add(a,b); printf("c =%d\n",c); return 0;
}1234567891011121314151617181920212223
gcc helloAdd.c -o helloAdd.out./helloAdd.out12
使用宏函数实现求和。
vim helloAddMacro.c1
#include #define R 20#define M int main(#define N(n) n*10#define ADD(a,b) a bint add(int a,int b){ return a b;
}M){ int a = R; printf("a =%d\n",a); printf("hello,world!\n"); int b =N(a); printf("b = %d\n",b); int c =add(a,b); printf("c =%d\n",c); int d =ADD(a,b); printf("d =%d\n",d); return 0;
}1234567891011121314151617181920212223242526
gcc helloAddMacro.c -o helloAddMacro.out./helloAddMacro.out12
可以看到使用宏函数和普通函数的求和效果是一致的。结果与简单的字符串替换一致。
ADD(a,b)
被替换成 a b
因此式子变成int d = a b;
gcc -o helloAddMacro.i helloAddMacro.c -E
vim helloAddMacro.i12
版本3,宏定义中优先级问题。
#include #define R 20#define M int main(#define N(n) n*10#define ADD(a,b) a bint add(int a,int b){ return a b;
}M){ int a = R; printf("a =%d\n",a); printf("hello,world!\n"); int b =N(a); printf("b = %d\n",b); int c =add(a,b); printf("c =%d\n",c); int d =ADD(a,b); printf("d =%d\n",d); int e =ADD(a,b) * ADD(a,b); printf("e =%d\n",e); return 0;
}1234567891011121314151617181920212223242526272829
预测一下e的输出为: a b*a b
ab先乘起来,a=20,b=200,ab=4000,然后加上a,b:得到结果(4220)
gcc helloAddMacroPrecedence.c -o helloAddMacroPrecedence.out./helloAddMacroPrecedence.out12
运算是等我们编译完了,执行的时候才会运行的。预处理阶段不会进行运算操作。
宏定义时由于本质是字符串的替换
真正运算的时候,会按照运算符号的优先级来进行
解决方案:
#define ADD(a,b) (a b)1
gcc helloAddMacroPrecedence.c -o helloAddMacroPrecedence2.out./helloAddMacroPrecedence2.out12
加个括号,保证优先级更高一点。
宏函数和正常函数的优势?
正常的add函数需要返回值类型,需要传递进来的参数有类型要求。
讲传入的a,b 类型进行改变,如变为两个浮点型数,程序就会自动类型转换。
但是宏函数就没有这种要求可以不用考虑输入值的类型,这与普通的函数定义不同。
int c =add(10.5,20.4);printf("c =%d\n",c);float d =ADD(10.5,20.4);printf("d =%f\n",d);12345
gcc helloAddMacroPrecedenceCompare.c -o helloAddMacroPrecedenceCompare.out./helloAddMacroPrecedenceCompare.out12
普通函数例如
int add(int a,int b)
除了在开头要声明值的类型,还要设置返回值,因此在定义过程与调用过程相对复杂。若能用宏定义实现的情况应优先考虑宏定义.
宏是不考虑数据类型,不考虑c语言的语法的。只是简单的字符串的处理。
预处理阶段,除了宏之外,还提供了一个叫做mtianyan:条件编译的功能。
可以按照不同的条件,编译不同的程序部分,从而产生不同的目标代码文件。对于程序的移植和调试都是很有用的。
下集预告: 和宏比较相近的功能,typedef
Linux C预处理之typedef
严格来讲,typedef
和预处理是没
Linux C语言结构体相关推荐
- linux中c语言结构体详解,Linux C语言结构体-学习笔记
Linux C语言结构体简介 前面学习了c语言的基本语法特性,本节进行更深入的学习. 预处理程序. 编译指令: 预处理, 宏定义, 建立自己的数据类型:结构体,联合体,动态数据结构 c语言表达式工具 ...
- linux c语言结构体初始化,Linux c中 结构体初始化方式
某日在看Linux底层驱动的介绍时,发现在Linux C中结构体的有多种初始化方式,这激起了我的好奇心,亲自实践,今日便来总结一下. 首先定义一个结构体:struct test{ int a; cha ...
- Linux+c语言结构体对齐,C语言中结构体struct的对齐问题解析
一:struct和union的区别 struct,相互关联的元素的集合,每个元素都有自己的内存空间:每个元素在内存中的存放是有先后顺序的,就是定义时候的顺序:一个struct所占的总的内存大小,并不是 ...
- python展开 c函数中的宏预处理_Linux C语言结构体-学习笔记
Linux C语言结构体简介 前面学习了c语言的基本语法特性,本节进行更深入的学习. 预处理程序. 编译指令: 预处理, 宏定义, 建立自己的数据类型:结构体,联合体,动态数据结构 c语言表达式工具 ...
- c语言2个字符串可以相互赋值吗,c语言结构体2之变量赋值于字符串
#include #include struct dangdang { char email[]; char name[]; char addr[]; int num; int bugnum; cha ...
- c语言结构体和联合体,C语言结构体和联合体
1.单链表插入 #include #include #define FALSE 0 #define TRUE 1 typedef struct NODE{ STRUCT NODE *link; int ...
- linux windows 结构体,Linux下C语言——结构体对齐
结构体对齐的步骤: 1.结构体各成员对齐 2.整个结构体圆整 结构体对齐的特定对齐值: 1.自身对齐值: 自身对齐值就是结构体变量里每个成员的自身大小; 2.指定对齐值: 指定对齐值是由宏#pragm ...
- linux c 结构体参数,C语言结构体类型定义
C语言结构体类型定义 结构体的定义形式如下: struct 结构体名 { 结构体成员 }: 结构体变量的定义方式有三种: 1.先定义结构体,再定义变量: eg. struct student{ cha ...
- 关于c语言结构体偏移的一点思考
注:此处只是利用了编译器的特性来计算结构体偏移 这句话就一笔带过,说得有点牵强附会.以后有时间自己再详细了解一下编译器的特性... more exceptional c++ 中文版 26页 https ...
最新文章
- Windows7 64bit VS2013 Caffe test MNIST操作步骤
- 新一代(New Generation)测试框架TestNG
- Aggregate累加器
- 指纹识别开发包 SourceAFIS
- 放出php压缩HTML函数,轻松压缩html、js和Css
- 传感器应用的demo自动录音器
- JavaScript基础事件(6)
- 用html5交换两个变量的值,Python判断两个对象相等的原理 python交换两个变量的值为什么不用中间变量...
- cdgb调试linux崩溃程序
- 1. BeeGo 介绍与项目的创建,启动
- Android 开发 学习网站
- 一台电脑能装两个版本的cad吗_同一台电脑装多个cad 电脑怎么装cad软件步骤
- autocad.net 画多段线_VB.net 在AutoCAD中绘制矩形云线
- msm8953 LCD移植详解
- Cobalt Strike上线微信机器人提醒
- 2014 c语言程序设计形成性考核册,C语言程序设计形成性考核册参考答案
- 为什么普遍使用Linux做服务器?
- 什么是大数据架构?需要学什么内容?
- 如何参加活动拿到华为实践证书?一起来吧~
- 补单平台-淘宝天猫补单平台-手工补单平台-靠谱的补单平台是什么样的
热门文章
- q7goodies事例_Java 8 Friday Goodies:Lambda和排序
- JMetro版本4.8已发布
- permgen_什么是PermGen泄漏?
- javaone_JavaOne 2012覆盖率
- ejb jsf jpa_完整的WebApplication JSF EJB JPA JAAS –第1部分
- 本周Java技巧#7 – Maven慢吗?
- uibinder表单提交_使用UIBinder的GWT自定义按钮
- 存根类 测试代码 java_为旧版代码创建存根-测试技术6
- Java 8 Friday:Java 8将彻底改变数据库访问
- 监控整页,非AJAX,要求通知