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");

C笔记(2014-12备份)的更多相关文章

  1. [原创] 【2014.12.02更新网盘链接】基于EasySysprep4.1的 Windows 7 x86/x64 『视频』封装

    [原创] [2014.12.02更新网盘链接]基于EasySysprep4.1的 Windows 7 x86/x64 『视频』封装 joinlidong 发表于 2014-11-29 14:25:50 ...

  2. 大型网站演化(转载 http://homeway.me/2014/12/10/think-about-distributed-clusters/)

    0x01.大型网站演化 简单说,分布式是以缩短单个任务的执行时间来提升效率的,而集群则是通过提高单位时间内执行的任务数来提升效率. 集群主要分为:高可用集群(High Availability Clu ...

  3. LAMP开发之环境搭建(2014.12.7在ubuntu下)

    Ubuntu下搭建LAMP环境 前言:学习PHP脚本编程语言之前,必须先搭建并熟悉开发环境,开发环境有很多种,例如LAMP.WAMP.MAMP等.这里我搭建的是LAMP环境,即Linux.Apache ...

  4. Android菜鸟的成长笔记(12)——Handler、Loop、MessageQueue

    原文:[置顶] Android菜鸟的成长笔记(12)——Handler.Loop.MessageQueue 当一个程序第一次启动时,Android会启动一条主线程(Main Thread),主线程主要 ...

  5. app后端设计(11)-- 系统架构(2014.12.05更新)

    个人认为,在小型的创业团队中,特别是以应用产品为主,在架构后台的时候,需要集中精力解决自身业务上的问题,不是花时间解决第三方已经解决的问题,简单点来说,就是能用第三方服务就使用第三方的服务.基于这个原 ...

  6. app后端设计(3)--短信,邮件,推送服务(2014.12.05更新)

    在app的后端设计中,免不了消息的推送,短信,邮件等服务,下面就个人的开发经验谈谈这方面. (1)最重要的是,各种推送一定要放在队列系统中处理,不然会严重影响api的响应时间. (2)短信方面 以前我 ...

  7. Django商城项目笔记No.12用户部分-QQ登录2获取QQ用户openid

    Django商城项目笔记No.12用户部分-QQ登录2获取QQ用户openid 上一步获取QQ登录网址之后,测试登录之后本该跳转到这个界面 但是报错了: 新建oauth_callback.html & ...

  8. [MVC学习日记]2014/12/01 初步认识MVC模型。

    2014/12/011.初步认识MVC模型.MVC模式是一种表现模式.它将web应用程序分成三个部分,模型(Model).视图(View).控制器(Controller).Model:是实现业务逻辑层 ...

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

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

  10. Flutter学习笔记(12)--列表组件

    如需转载,请注明出处:Flutter学习笔记(12)--列表组件 在日常的产品项目需求中,经常会有列表展示类的需求,在Android中常用的做法是收集数据源,然后创建列表适配器Adapter,将数据源 ...

随机推荐

  1. Windows命令行查看相关信息

    Windows命令行查看相关信息 查看网络相关 查看网络相关 netstat -ano |findstr -v 127 |findstr -v 10.110 |findstr -v 10.6 |fin ...

  2. 【JS 逆向百例】转变思路,少走弯路,X米加密分析

    声明 本文章中所有内容仅供学习交流,抓包内容.敏感网址.数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除! 逆向目标 目标:X米账号登 ...

  3. mysql系列基础篇03----约束

    一.概述 1.概念:约束是作用于表中字段上的规则,用于限制存储在表中的数据 2.目的:保证数据库中数据的正确,有效性和完整性. 3.分类  二.约束演示 创建一个用户表 create table my ...

  4. Java中的基本数据类型和包装类型的这些知识,你都知道吗?

    Java中的基本数据类型和包装类型 Java 中的基本数据按类型可以分为四大类:布尔型.整数型.浮点型.字符型: 这四大类包含 8 种基本数据类型. 布尔型:boolean 整数型:byte.shor ...

  5. 从零开始配置vim(27)——代码片段

    我们之前介绍过缩写相关的内容,缩写是可以自动帮我们将缩写的单词展开成一段完整的话.但是代码本身是结构话的,仅仅使用缩写来配置是无法完成自动生成代码这个步骤的.好在我们大量的插件来进行配置.本篇我们将要 ...

  6. WebAssembly入门笔记[3]:利用Table传递引用

    在<WebAssembly入门笔记[2]>中,我们介绍了如何利用Memory在作为宿主的JavaScript应用和wasm模块之间传递数据,但是Momory面向单纯二进制字节的读写在使用起 ...

  7. 从github上下载代码到本地

    相关链接: 码云(gitee)配置SSH密钥 码云gitee创建仓库并用git上传文件 git 上传错误This oplation equires one of the flowi vrsionsot ...

  8. MySQL 字符串与时间操作函数

    MariaDB [lyshark]> select Name,char_length(Name) from lyshark; -- 求字符串长度 +------------+---------- ...

  9. Linux 文件目录操作命令

    Linux 基础的文件目录操作命令,融合多部Linux经典著作,去除多余部分,保留实用部分. 显示目录或文件: 显示目标列表,在Linux系统中是使用率较高的命令.ls命令的输出信息可以进行彩色加亮显 ...

  10. Gin 获取请求参数

    1.获取URL?后的参数(不区分请求方式) // 获取请求url ? 后的参数(url:8080/add?name=kelvin) func GetUrlParam(ctx *gin.Context) ...