day11嵌入式(2022.1.17)

简介: day11嵌入式(2022.1.17)
  1. gcc编译器有什么用?


将代码文本编译为机器能识别的二进制指令。


  1. 从代码最终得到程序,经过了哪4个步骤?


预处理、编译、汇编、链接


  1. 经过哪个步骤之后,代码不能直接阅读了?


汇编。


  1. 对于代码的语法检查(提示错误行号)属于在哪个步骤进行?


编译。


  1. 为什么代码漏写函数,gcc编译时不提示出现错误的行号?


因为函数链接定位在链接的阶段,而不是在编译阶段。


1.gcc编译流程



  1. 预处理:(代码文本 ---> 预处理文本)


指令:gcc hello.c -o hello.i -E


作用:处理所有的预处理指令(以#开头,比如头文件包含、宏定义、条件编译)


  1. 编译:(预处理文本 ---> 汇编文件)


指令:gcc hello.i -o hello.s -S


作用:词法、语法分析,根据平台生成最接近机器的语言(汇编)。


  1. 汇编:(汇编文件 ---> ELF可重定位文件)


指令:gcc hello.s -o hello.o –c


作用:将汇编指令文件翻译为可直接运行的二进制指令流。


  1. 链接:(ELF可重定位文件 + 库链接 ---> 最终程序)


指令:gcc hello.o -o hello –lc -lgcc


作用:重定位(函数和全局变量等)、链接库、合并段


备注:


  1. 汇编阶段,是处理汇编文件,生成二进制机器指令。


  1. -lXXX表示链接XXX库(-l: library)


  1. 预处理阶段,不会对代码进行语法词法分析。


  1. 链接阶段会对所有函数、全局变量进行重定位、链接,如果此时出现问题,不会提示出错行号。


2.预处理指令



在源码中,以#开头的语句,称为预处理指令,他们不属于C语言语法。


  1. 宏定义


#define PI 3.1415926    // 预处理阶段中,将代码中所有宏进行替换。


  1. 条件编译(有点类似于分支结构)


#if #ifdef #ifndef #elif #else #endif


  1. 头文件包含


#include <stdio.h>


备注:


  1. 宏名一般使用全大写字母,用以区别普通变量、函数。


  1. 带参宏,也称为宏函数,但是不存在函数调用机制。


  1. 宏定义的作用:


  • 可使代码更具可读性:字符单词一般比纯数字更容易理解含义。


  • 使得代码更方便修改:只需修改宏定义,即修改了所有该宏定义表达式。


  • 提高程序运行效率:函数的调用是需要切换时间的,而宏定义是直接展开,不占用运行时间。


gcc编译指令中,可添加 -D选项,往工程中添加指定的宏。


可添加一些调试语句,通过编译指令去控制调试语句的输出。


gcc demo4_条件编译ifdef-ifndef.c -o demo –DTEST


条件编译属于预处理指令,在预处理阶段就已经完成了判断,程序运行过程中不会再次判断。


下列语句可避免头文件中的内容重复加入编译:



demo1_编译过程


#include <stdio.h>
#include <string.h>
void hahaha(char *str);
int main()
{
  printf("hello world.\n");
  hahaha("hello world.\n");
  return 0;
}


demo2_define宏定义


#include <stdio.h>
#include <string.h>
// 不带参宏
// #define PI
#define PI 3.1415926  // 预处理阶段中,将代码中所有宏进行替换。
// 带参宏(宏函数)
#define SUM(a,b) (a+b)
// 子函数
float func_sum(float a, float b);
int main()
{
  printf("hello world.\n");
  float r = 5.0;
  printf("面积: %f\n", PI*r*r);
  printf("周长: %f\n", 2*PI*r);
  float var1 = 1.2;
  float sum = func_sum(r, var1)*2;
  printf("sum: %f\n", sum);
  sum = SUM(r, var1)*2;
  printf("sum: %f\n", sum);
  return 0;
}
float func_sum(float a, float b)
{
  return a+b;
}


demo3_条件编译_if-else


#include <stdio.h>
#include <string.h>
int main()
{
#if 0
  printf("hello world.\n");
  printf("hello world.\n");
  printf("hello world.\n");
  printf("hello world.\n");
  printf("hello world.\n");
  printf("hello world.\n");
#else
  printf("nihao 123.\n");
  printf("nihao 123.\n");
  printf("nihao 123.\n");
  printf("nihao 123.\n");
  printf("nihao 123.\n");
  printf("nihao 123.\n");
#endif
  return 0;
}


demo4_条件编译ifdef-ifndef


#include <stdio.h>
#include <string.h>
int main()
{
#ifdef TEST
  printf("[%d]\n", __LINE__);
#endif
  printf("nihao 123.\n");
  printf("nihao 123.\n");
  printf("nihao 123.\n");
  printf("nihao 123.\n");
  printf("nihao 123.\n");
  printf("nihao 123.\n");
#ifdef TEST
  printf("[%d]\n", __LINE__);
#endif
  return 0;
}


demo5_使用自己的头文件


#include <stdio.h>
#include <string.h>
  // 包含系统头文件
#include "myhead.h"
#include "myhead.h"
#include "myhead.h"
#include "myhead.h"
#include "myhead.h"
#include "myhead.h"
#include "myhead.h"
#include "myhead.h"
#include "myhead.h"
#include "myhead.h"
  // 包含自定义头文件
int main()
{
  printf("%d\n", ABC);
  return 0;
}


myhead.h


#ifndef _MYHEAD_H
#define _MYHEAD_H
#define ABC 1234
#endif
相关文章
|
6月前
|
Linux API C语言
嵌入式
嵌入式
90 2
|
5月前
|
C语言
嵌入式程设
嵌入式程设
|
存储 Java C#
day10嵌入式(2022.1.16)
day10嵌入式(2022.1.16)
|
传感器 人工智能 安全
有什么是嵌入式不能满足的?
从20世纪60年代开始,嵌入式系统就已经开始出现,当时主要应用于航空航天、国防、工业自动化等领域
|
存储
day7嵌入式(2022.1.13)
day7嵌入式(2022.1.13)
|
机器学习/深度学习 C语言
嵌入式day5(2022.1.11)
嵌入式day5(2022.1.11)
|
C语言
嵌入式day4(2022.1.10)
嵌入式day4(2022.1.10)
|
存储 编译器
day8嵌入式(2022.1.14)
day8嵌入式(2022.1.14)
|
数据安全/隐私保护 C语言
day12嵌入式(2022.1.18)
day12嵌入式(2022.1.18)
|
传感器 设计模式 Ubuntu
嵌入式到底该怎么学
其实一直有人问我嵌入式怎么学,今天跟大家讲讲我的理解。因为嵌入式是一个泛的概念,可能很多人认为嵌入式就是嵌入式Linux。但是其实并不仅仅只有Linux, 像STM32,51单片机也属于这个范畴之内的,它们有的也可以跑协议栈,跑ucos等系统。所以其实嵌入式是有很多方向的,选择一个方向,做好,做精,都是有前途的。接下来,跟大家探讨一下嵌入式的一些方向,和如何去学习。我以前也是摸索着过来的,没人告诉我如何学习,也没有学习线路,所以走了很多弯路。所以希望这篇文章可以帮助到一些正在学习的人,当然这些内容可能有主观的东西,欢迎大家一起探讨吧。