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备份)相关推荐

  1. Linux第二周学习笔记(12)

    Linux第二周学习笔记(12) 2.18 特殊权限set_uid set_uid:这个权限是针对二进制可执行文件,使文件在执行阶段具有文件所有者的的权限. --------------------- ...

  2. 《C Primer Plus》学习笔记—第12章

    目录 <C Primer Plus>学习笔记 第12章 存储类别.链接和内存管理 1.存储类别 1.作用域 2.链接 3.存储期 4.自动变量 1.程序hiding.c 2.没有花括号的块 ...

  3. Java程序猿的JavaScript学习笔记(12——jQuery-扩展选择器)

    计划按例如以下顺序完毕这篇笔记: Java程序猿的JavaScript学习笔记(1--理念) Java程序猿的JavaScript学习笔记(2--属性复制和继承) Java程序猿的JavaScript ...

  4. springboot学习笔记:12.解决springboot打成可执行jar在linux上启动慢的问题

    springboot学习笔记:12.解决springboot打成可执行jar在linux上启动慢的问题 参考文章: (1)springboot学习笔记:12.解决springboot打成可执行jar在 ...

  5. ElasticSearch 6.x 学习笔记:12.字段类型

    ElasticSearch 6.x 学习笔记:12.字段类型 欢迎转载. https://blog.csdn.net/chengyuqiang/article/details/79048800 12. ...

  6. C# 学习笔记(12)hex文件转bin文件小工具

    C# 学习笔记(12)hex文件转bin文件小工具 hex文件格式 hex文件格式网上有很多 我这里参考HEX文件格式详解https://blog.csdn.net/weixin_39752827/a ...

  7. 台湾国立大学郭彦甫Matlab教程笔记(12) advanced 2D plot 下

    台湾国立大学郭彦甫Matlab教程笔记(12) advanced 2D plot 下 上文记录的是关于统计的图标的绘制 下面我们来到另一个模块:颜色 fill()填充函数 功能:某一个封闭曲线,图上特 ...

  8. 44-当日交易总结。(2014.12.31)

    44-当日交易总结 1.趋势抓的很好时,在低位近.在高位出.也许收益做的很不错,但是人在高度专注情况下,容易疲劳.这会导致一轮交易即使做的很好,在准备下一轮交易时会出现体力不支的现象.所以,不要熬夜, ...

  9. Git笔记(12) 分支使用

    Git笔记(12) 分支使用 1. 使用场景 2. 新建并切换iss分支 3. 推进iss分支 4. 切回master分支 5. 新建并切换hotfix分支 6. 合并hotfix分支 7. 删除ho ...

  10. 视觉SLAM笔记(12) 四元数

    视觉SLAM笔记(12) 四元数 1. 定义 2. 运算 2.1. 加法和减法 2.2. 乘法 2.3. 共轭 2.4. 模长 2.5. 逆 2.6. 数乘与点乘 3. 旋转表示 4. 旋转矩阵转换 ...

最新文章

  1. HTTP、SSL、TLS,HTTPS简单介绍
  2. PS Material 漫谈 六: Material Availability Check
  3. mybatis-plusspringboot
  4. 不安装cudnn可不可以_关于CUDA和cuDNN的安装
  5. 系统提示一个程序正在被另一个程序调用,如何知道是被哪个程序调用
  6. 系统10网络找不到别人的计算机,分享Win10在局域网中找不到其他电脑的解决步骤...
  7. 001 Hello Security 的框架搭建
  8. Python统计共同参演电影最多的演员组合
  9. SqlServer之OutPut
  10. twisted python_Python爬虫Scrapy框架之Hello Word
  11. mysql——event定时任务
  12. bigdecimal java 最大值_Java中的数学运算BigDecimal
  13. adb双击POWER键指令
  14. 判断入射满射c语言编码,数学上可以分三类函数包括() 答案:单射双射满射...
  15. BaseFX 实习小记(四)
  16. C# dotnet 获取某个字符所在 Unicode 字符平面映射
  17. containerd 拉取k8s.gcr.io/pause镜像i/o timeout
  18. 《软件方法》第8章 分析 之 分析类图(2)
  19. WPS自定义样式功能太弱了
  20. 新版TCGA不同癌种数据合并

热门文章

  1. Oracle Sql技巧 - Upsert, Multitable Insert, Undrop
  2. mysql之select查询
  3. 状态保持中的cookie
  4. xp系统下访问的两个组策略设置
  5. centos7安装vsftpd
  6. 如何安装Android SDK Emulator
  7. python,day13-堡垒机
  8. 怪不的软件开发这么挣钱,原来是有这么多职位
  9. 查看 -- tree
  10. Tomcat如何添加管理员