C笔记(2014-12备份)
Video1:
1-编译器对待全局变量和局部变量的差别。全局变量分配空间是在数据区,局部变量分配在代码区. (比如局部变量 int lo_var = 2;后面的 = 2;是赋值语句,被编译器转化成机器指令,分配的空间在栈上。全局变量 int gl_var = 2; 编译器认为这是一个在数据区要分配的变量,数据区增加4个字节,后面的= 2;只不过是这个变量的初始值。)
2-数据区提取linux命令:
objcopy -O binary -j .data a.out date.bin
3-代码区提取:
objcopy -O binary -j .text a.out text.bin
4-gcc -S code.c 生成一个汇编程序
5-hexdump -C a.out 十六进制查看a.out。可以发现文件头是ELF,点号表示不可显示字符
6-readelf -a a.out 查看elf。我们可以从结果中看到ELF Headers(ELF头)、 Section Headers(节头)、program Headers(段头)、Section to segment mapping(节到段的映射)、Dynamic Section...(动态链接信息)、Symbol Table(符号表)等信息
7-更多关于linux可执行文件的知识,可以参考《Linux 一站式编程》。推荐书籍《程序员的自我修养》
Video2:
1-增量式开发方式
2-打印main函数的地址不需要取地址符号&
例如: printf("Memery address: &num(global) is %p, &lo_int(local) is %p, main is %p\n", &num, &lo_int, main); //可以使用%x,建议使用%p
//回显:Memery address: &num(global) is 0x600970, &lo_int(local) is 0x7ffd56e6a26c, main is 0x400506
//发现: 发现全局变量的地址较小,局部变量的地址比较大
3- 系统头文件包含用#include <>
Video3-4:
1- cat stdio.h,我们看到了printf的声明 extern int printf (const char *__restrict __format, ...);
2- gcc -E a.c // -E表示预处理 ,如果a.c中用到了printf函数,则可以在gcc -E预处理输出中看到extern int printf (const char *__restrict __format, ...);
3-gcc -v code.c可以查看详细编译过程(从预处理后的源码到二进制码的过程),其中发现cc1才是真正负责编译的(gcc包含了编译链接的全过程),也可以看到cc1编译成汇编时用到的选项参数。-o选项后面的文件是编译产生的汇编文件名(扩展名.s)。cc1命令生成汇编文件后执行as命令,as是将汇编文件生成扩展名为.o的目标文件(可以看到选项参数)。as命令执行完后,用collect2命令(链接器)来将目标文件链接成elf文件(选项-lc中l表示链接,c表示c库。合起来-lc表示要参与链接的是c库文件libc.a)
4-反汇编 objdump -d a.out 将a.out的所有机器指令(地址 二进制 对应汇编命令). 通过反汇编,我们可以看到call 调用函数(如printf),看到cmpl(cmp比较,l长整型),jle(j跳转,后面le表示小于等于). 通过观察jle左边的机器指令,我们发现机器指令中并未包含jle后面要跳转的地址,是数据相对跳转,jle后面有个main+0x27表示,表示跳转的地址是在main后0x27位置。这就是地址无关代码。
而mov后面,有个绝对地址(0x8048553),我们能在mov的前面的机器指令中发现53 85 04 08 (反过来阅读08 04 85 53)。这个是绝对跳转。
5-ld --verbose 这个命令可以打印出默认的链接脚本。可以查看到默认的可执行部分起始地址是0x多少(例如回显:PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;),我们打印main函数地址的时候,就是这个数字后面一点点,全局变量也比较接近这个地址。
6- extern _start //外部声明
init main(void)
...
print("_start=%p", &_start) //打印出c程序入口的地址(程序代码段的起始地址,main函数在_start之后,所以main函数不是真正的程序入口)
...
7-反汇编过程能看到一些地址(位置)无关代码(PLC position independentless code)。跳转是相对位移,而不是绝对位移,那么指令移动了地址也可以执行。
8- 32位的linux上,局部变量的地址在3G左右(32bit linux的最大内存分配)。c程序中打印的地址是虚拟地址,真实地址无法看到,操作地址会将虚拟地址转化为真实地址。
9- 风格示例(循环前赋初值):
void main(void)
{
int counter = 0; //定义局部变量时赋初值,赋初值可以避免后面忘记赋值而导致的该变量为不确定值。
...
counter = 0; //循环变量赋初值靠近循环体,方便循环的初值的修改。
while (counter < 100)
{
...
}
...
}
Video5:
1-一般我们定义一个局部变量时赋初值。(反例:比如int num;printf("num=%d\n",num); 回显-1217359884)
2-运行时错误,编译时错误
3-对于值判断,可以将值写左边,这样编译器可以帮我们检查一些错误。 例如 if(0 == num)
4- int var; scanf("%d", &var); //如果输入abc100,则var值为0;如果输入100abc,则var值为100。
5- 段错误(Segmentation Fault),这个错误导致程序无法执行下去。(比如scanf忘记&取地址符号)
Video6-7:
1- c99中允许变量定义在for循环中。例如:for(int i = 0, sum = 0; i <= 100; i++) ,此时sum和i只能作用于for循环体
2-变量的种类: 全局变量、局部变量、自动变量
3- gcc -std=c99 a.c //使用c99标准编译
4-调试宏示例:
#include <stdio.h>//#define PRINT(x,y,z) printf("<debug> " #x "=%d, " #y "=%d, " #z "=%d\n", x, y, z) //#号表示强制转换为同等的字符串 #define PRINT(x,y,z) //当前调试后int main(void) { int yr = 0; int mn = 0; int dy = 0;int ref_day = 5; // Jan 01 2016 is friday int mon[12] = {31,29,31,30,31,30,31,31,30,31,30,31} ;printf("get the day in 2016\n");printf("pls input a date in 2016(format is yyyy mm dd):"); scanf("%d%d%d", &yr ,&mn, &dy); PRINT(yr, mn, dy); /* ...省略后面的语句... */ return 0; }
Video8:
1-查询某个函数属于什么库,可以直接man
2-编译时的链接错误可以通过man 库名知道编译的时候需要带什么参数。例如#include <math.h>后调用sqrt()函数提示编译缺少库,通过man sqrt知道编译的时候需要加入-lm选项
3-条件编译:#if DEBUG
statement
#endif
编译的时候,gcc -DDEBUG (-D表示定义宏)。不要DEBUG则编译的时候gcc -UDEBUG (-U表示取消宏)。
Video9-10:
注释示例:/** sum9-2.c - sumary how many digit from 1 to 100** Author: li ming <limingth@gmail.com>* Create Date: 2013-3-26* Revision 1.1* + debug printf*/ #include <stdio.h>/** count - count how many digit in num* @num: the number from 1 to 100* @digit: digit can be 0, 1, 2, 3, ... 9** return value: the counter of digit in this num*/ int count(int num, int digit) {int counter = 0;do{if (num % 10 == digit)counter++;num /= 10;} while (num != 0);return counter; }int main(void) {int i = 0;int sum = 0; /* the sumary of 9 */int max = 0; /* the max number to count */printf("sumary 9 from 1 to 100\n");scanf("%d", &max);/* sumary 9 from 0 to max */for (i = 0; i <= max; i++){sum += count(i, 9); }printf("sum = %d\n", sum);return 0; }
Video11:
1- ascii转换
int a = 3;
printf("%s", a + 30); //回显3,3的ascii码30
printf("%s", a + '0'); //回显3,这里的'0'等价于ascii码30
2-char型数数组中,\0表示字符串的结束。例如char str[5] = {'a', 'b', '\0', 'd', '\0'}; printf("%s", str); //只回显ab
3- char str[5] ; str[0] = 'a'; printf("%s", str); //回显的a后面可能有未预期的字符,所以需要用\0结束字符串
Video12:
1-通过传参来获得返回值(返回传入的空值变量)
2-注意对形参中的字符数组的形式。void itoa(int num, char buf[])
3-永恒为假的条件编译:
#if 0
code block
#endif
4-宏定义必须在一行内写完,所以多行,需要用续行符\
5-宏定义来实现类似函数的功能(这里是交换变量)。(注意分号、花括号在if-else中的副作用:else前不可以分号。使用do-while来规避分号的缺陷)16min
副作用的原理类似如下代码(注意花括号后面有分号):
if ( 1 == 1 )
{
printf("test\n");
}
;
else
printf("test2\n");
转载于:https://www.cnblogs.com/mind-water/articles/c_01.html
C笔记(2014-12备份)相关推荐
- Linux第二周学习笔记(12)
Linux第二周学习笔记(12) 2.18 特殊权限set_uid set_uid:这个权限是针对二进制可执行文件,使文件在执行阶段具有文件所有者的的权限. --------------------- ...
- 《C Primer Plus》学习笔记—第12章
目录 <C Primer Plus>学习笔记 第12章 存储类别.链接和内存管理 1.存储类别 1.作用域 2.链接 3.存储期 4.自动变量 1.程序hiding.c 2.没有花括号的块 ...
- Java程序猿的JavaScript学习笔记(12——jQuery-扩展选择器)
计划按例如以下顺序完毕这篇笔记: Java程序猿的JavaScript学习笔记(1--理念) Java程序猿的JavaScript学习笔记(2--属性复制和继承) Java程序猿的JavaScript ...
- springboot学习笔记:12.解决springboot打成可执行jar在linux上启动慢的问题
springboot学习笔记:12.解决springboot打成可执行jar在linux上启动慢的问题 参考文章: (1)springboot学习笔记:12.解决springboot打成可执行jar在 ...
- ElasticSearch 6.x 学习笔记:12.字段类型
ElasticSearch 6.x 学习笔记:12.字段类型 欢迎转载. https://blog.csdn.net/chengyuqiang/article/details/79048800 12. ...
- C# 学习笔记(12)hex文件转bin文件小工具
C# 学习笔记(12)hex文件转bin文件小工具 hex文件格式 hex文件格式网上有很多 我这里参考HEX文件格式详解https://blog.csdn.net/weixin_39752827/a ...
- 台湾国立大学郭彦甫Matlab教程笔记(12) advanced 2D plot 下
台湾国立大学郭彦甫Matlab教程笔记(12) advanced 2D plot 下 上文记录的是关于统计的图标的绘制 下面我们来到另一个模块:颜色 fill()填充函数 功能:某一个封闭曲线,图上特 ...
- 44-当日交易总结。(2014.12.31)
44-当日交易总结 1.趋势抓的很好时,在低位近.在高位出.也许收益做的很不错,但是人在高度专注情况下,容易疲劳.这会导致一轮交易即使做的很好,在准备下一轮交易时会出现体力不支的现象.所以,不要熬夜, ...
- Git笔记(12) 分支使用
Git笔记(12) 分支使用 1. 使用场景 2. 新建并切换iss分支 3. 推进iss分支 4. 切回master分支 5. 新建并切换hotfix分支 6. 合并hotfix分支 7. 删除ho ...
- 视觉SLAM笔记(12) 四元数
视觉SLAM笔记(12) 四元数 1. 定义 2. 运算 2.1. 加法和减法 2.2. 乘法 2.3. 共轭 2.4. 模长 2.5. 逆 2.6. 数乘与点乘 3. 旋转表示 4. 旋转矩阵转换 ...
最新文章
- HTTP、SSL、TLS,HTTPS简单介绍
- PS Material 漫谈 六: Material Availability Check
- mybatis-plusspringboot
- 不安装cudnn可不可以_关于CUDA和cuDNN的安装
- 系统提示一个程序正在被另一个程序调用,如何知道是被哪个程序调用
- 系统10网络找不到别人的计算机,分享Win10在局域网中找不到其他电脑的解决步骤...
- 001 Hello Security 的框架搭建
- Python统计共同参演电影最多的演员组合
- SqlServer之OutPut
- twisted python_Python爬虫Scrapy框架之Hello Word
- mysql——event定时任务
- bigdecimal java 最大值_Java中的数学运算BigDecimal
- adb双击POWER键指令
- 判断入射满射c语言编码,数学上可以分三类函数包括() 答案:单射双射满射...
- BaseFX 实习小记(四)
- C# dotnet 获取某个字符所在 Unicode 字符平面映射
- containerd 拉取k8s.gcr.io/pause镜像i/o timeout
- 《软件方法》第8章 分析 之 分析类图(2)
- WPS自定义样式功能太弱了
- 新版TCGA不同癌种数据合并