C/C++|物联网开发入门+项目实战|嵌入式C语言高级|简介及GCC参数|define|编译过程-学习笔记(7)

本课程关注嵌入式C语言的高级概念,包括GCC工具的使用、编译过程、常见错误类型如预处理错误、链接错误和宏的使用。讲解了如何通过gcc命令行选项控制编译过程,以及如何解决头文件找不到、函数未定义等链接问题。还涉及了宏定义的技巧,如字符串化和连接符号。
摘要由CSDN通过智能技术生成

课程介绍

参考:麦子学院-嵌入式C语言高级

本套课程的定位

前导课程:掌握简单C语言的基本语法
计算机程序语言的学习思路?
基本程序设计思想+语言工具的特性
基本程序设计思想:
数据类型、运算符、条件分支、循环设计
面向对象的设计
C语言工具的特性:
比如操作底层,尤其是内存地址的寻址及操作,指针的使用
掌掘C语言的设计思路,比普通的语法要重要的多
万变不离其宗,掌掘C语言的核心规律。

本套读程的想法

不是教程,是一种嵌入式C语言思想和设计的交流
什么时候用?
怎么用?
为什么要这样设计?

推荐教程

C语言深度解剖(第2版》 解开程序员面试笔试的秘密
C专家编程
程序员面试宝典《第4版)
C和指针

偏重嵌入式方向的使用

嵌入式课程的特点

2-1 : GCC的使用及其常用选项介绍【重点】

掌握C语言如何变成机器指令的过程
gcc工具的几个常用选项的意义
【难点】
C编译过程中在gcc工具上的体现
【实验考核】
自己编写程序,利用gcc工具集验证每一步的执行效果
举例说明gcc选项的意义:
gcc -I gcc -L
gcc -E gcc -S gcc -c

Gcc概述

c语言的编译过程
可参考:C/C++|物联网开发入门+项目实战|C语言基础|C语言的预处理及编译过程分析-学习笔记(2)

C语言常见错误举例

预处理错误;

include “name” 当前目录
include 系统库(环境变量)

not find

示例
从abc1.h中引入字符char_c

#include <stdio.h>
#include "abc1.h"

int main()
{
    char  c=char_c;
    printf("c(char)=%c,c(int)=%d,c_change(char)=%c,c_change(int)=%d,c_change(HEX)=%#x\n",c,c,c+32,c+32,c+0x20);
    return 0;
}

输出:
E:\temp>cd “e:\temp” && gcc 2.c -o 2 && "e:\temp"2
2.c:2:18: fatal error: abc1.h: No such file or directory
compilation terminated.
显然无此文件(文件名错误),改为include “abc.h”,运行正常。
而一般地,将头文件一般放在inc目录下。
建立inc,并把abc.h移入inc:
在这里插入图片描述

1、方法1:修改inclue为#include “./inc/abc.h”;
2、方法2:gcc -I ./inc 2.c -o 2

编译错误

语法错误,

链接错误

打包出错,原材料不够 undefined reference

寻找标签是否实现了,链接时是否加入一起链接
示例

#include <stdio.h>
#include "abc.h"

void fun(void);
int main()
{
    char  c=char_c;
    printf("c(char)=%c,c(int)=%d,c_change(char)=%c,c_change(int)=%d,c_change(HEX)=%#x\n",c,c,c+32,c+32,c+0x20);

    fun();
    return 0;
}

main函数中引用了一个fun函数,但没有fun函数的实现,故链接器collect2.exe时出错,

提示:
E:\temp>gcc -I ./inc 2.c -o 2 && "e:\temp"2
C:\Users\Vera\AppData\Local\Temp\ccRNGpif.o:2.c:(.text+0x4b): undefined reference to `fun’
collect2.exe: error: ld returned 1 exit status
解决方法1:不声明,删除fun()的定义并直接实现一个空函数:

void fun(void)
{

}

方法2:2.c不变,新建立abc.c存放fun()的函数实现,如:
abc.c

void fun(void)
{

}

执行程序:>gcc -I ./inc -o 2 2.c abc.c #将所有用到的原材料放在输出文件之后
方法3:分别编译再拼接

E:\temp>gcc -c -I./inc -o a.o 2.c
E:\temp>gcc -c  -o b.o abc.c

分别编译完成后的文件都输出在当前目录下:

gcc -o 2 a.o b.o
原材料多了(重复定义) multiple definition

解决思路:多次实现了标签,只保留一个标签实现
在2个文件中都实现fun()函数,并重新编译,链接:

E:\temp>gcc -c -I./inc -o a.o 2.c

E:\temp>gcc -c  -o b.o abc.c

E:\temp>gcc -c -I./inc -o a.o 2.c

E:\temp>gcc -o 2 a.o b.o

提示错误:
E:\temp>gcc -o 2 a.o b.o
b.o:abc.c:(.text+0x0): multiple definition of `fun’
a.o:2.c:(.text+0x0): first defined here
collect2.exe: error: ld returned 1 exit status

宏的使用

预处理的使用

#include 包含头文件,并在当前位置展开
#deine 宏(替换),不进行语法检查,编译时才检查
#define 宏名 宏体 加括号
#define ABC (5+3)
#define ABC(x) (5+(x)) //宏函数

预定义宏(方便调试)

(C语言编译器或gcc定义)
前后2个下划线
FUNCTIO
LINE
FILE

示例

#include <stdio.h>

int main()
{

     //本行执行的函数名,所在文件名,本行的行号
    printf("the %s,%s,%d\n",__FUNCTION__,__FILE__,__LINE__);

    return 0;
}

输出:
E:\temp>cd “e:\temp” && gcc 2.c -o 2 && "e:\temp"2
the main,2.c,7

改示例为

#include <stdio.h>

int fun()
{
    int a;

     //本行执行的函数名,所在文件名,本行的行号
    printf("the %s,%s,%d\n",__FUNCTION__,__FILE__,__LINE__);

    return 0;
}

int main()
{
    fun();

    return 0;
}

输出(实际调用的函数名称和所在行号):
E:\temp>cd “e:\temp” && gcc 2.c -o 2 && "e:\temp"2
the fun,2.c,8

条件预处理

#ifdef #else #endif
调试版本

发行版本
示例
原始代码:

#include <stdio.h>

int main()
{
    printf("=========================\n",__FILE__);

    printf("hello world!\n");

    return 0;
}

debug期间允许__FILE__行显示,但发行版本中不显示,怎么实现:

#include <stdio.h>

int main()
{
#ifdef  ABC

    printf("=========================\n",__FILE__);

#endif

    printf("hello world!\n");

    return 0;
}

未定义ABC时,不打印:

E:\temp>cd “e:\temp” && gcc 003.c -o 003 && "e:\temp"003
hello world!

需要显示调试信息时,只要在#ifdef ABC之前定义ABC即可。
在这里插入图片描述
但是该方法还是要修改源文件,不是很方便,故引入gcc -D:cpp之前增加define
如:gcc -DABC -o build 003.c 相当于编译前引入: #define ABC。

宏展开下的#、##

# 字符串化
## 连接符号
#define ABC(x) #x
#define ABC(x) day##x //day和x进行连接

示例
#include <stdio.h>
#define ABC(x)    #x //字符串化
#define DAY(x)    myday##x //字符串在当前位置展开,可以执行调用前,后缀
int main()
{
    int a;
    int myday1 = 10;
    int myday2 = 20;
     //本行执行的函数名,所在文件名,本行的行号
    // printf("the %s,%s,%d\n",__FUNCTION__,__FILE__,__LINE__);
    printf(ABC(ab\n));   //相当于:"ab\n"
    printf("the day is %d\n",DAY(1)); //前缀或者后缀以隐藏方式调用。
    printf("the day is %d\n",DAY(2));
    return 0;
}

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Visual C++从初学到精通 吕兵 高清PDF带书签 《Visual C++从初学到精通》由浅入深:逐步展现VistJal c++开发中的核心Wiridows编程机制;重点突出:详细讲解Wiridows编程和数据库开发两个典型方向;实例典型:用52个典型实例讲解VisuJaI c++开发的重点知识;侧重开发:包含数据库、网络通信、Windows组件三大开发方向;注重实战:用2个完整案例展现Visual c++开发应用流程和领域。 光盘内容: 《Visual C++从初学到精通》实例源代码 《Visual C++从初学到精通》多媒体教学视频 《Visual C++从初学到精通》教学PPT 免费赠送的电子图书和视频 《Visual C++从初学到精通》涵盖内容:控制台应用程序、基于对话框的应用程序、单文档应用程序、多文档应用程序、异常处理机制、 Windows应用程序运行机;WinMain()函数、MFC消息映射机制、API文件操作、MFC文件操作、创建位图对象、模态对话框、菜单的创建、工具栏的使用、状态栏的创建、进程和线程的基本概念、Win32的进程处理、Win32的线程处理、MFC的线程处理、线程同步、ODBC组成结构使用ODBC API进行数据库开发、DAO编程方法、ADO对象模型、套接字、客户机/服务器模式、网络字节顺序、半相关与全相关、半双工与全双工、 套接字编程模型、Windows Socket API主要函数、MFC Socket编程、Winlnet编程、创建动态链接库、使用ActiveX控件编写ActiveX控件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

打酱油的工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值