C语言进阶
文章平均质量分 89
主要以C语言为主
strongercjd
资深嵌入式软件开发工程师,分享嵌入式软硬件方面知识。
展开
-
预编译#error的使用
说到预编译,大家立刻就能想到#define、#if、#ifdef和#ifndef等熟悉的预编译命令。其实#include,我们通常放在源文件用来包含头文件,它也是预编译命令。当然这不是这篇文章的重点。这篇文章主要讲解下#error预编译命令,对于什么是预编译,预编译的作用等基础知识点不再讲解,不懂的同学请自行百度。在MCU的开发中,我们经常需要用到Flash存储一些参数,且通常情况下有很多参数需要存储。原创 2022-12-17 10:57:18 · 1193 阅读 · 2 评论 -
表驱动法在STM32中的应用
所谓表驱动法(Table-Driven Approach)简而言之就是用查表的方法获取数据。此处的“表”通常为数组,但可视为数据库的一种体现。根据字典中的部首检字表查找读音未知的汉字就是典型的表驱动法,即以每个字的字形为依据,计算出一个索引值,并映射到对应的页数。相比一页一页地顺序翻字典查字,部首检字法效率极高。具体到编程方面,在数据不多时可用逻辑判断语句(if…else或switch…case)来获取值;但随着数据的增多,逻辑语句会越来越长,此时表驱动法的优势就开始显现。原创 2022-11-05 23:48:32 · 3390 阅读 · 2 评论 -
聊聊数据溢出的事
聊聊数据溢出的事情原创 2022-07-09 11:38:07 · 640 阅读 · 0 评论 -
C语言为什么不检查数组下标
1、引言最近在查一个bug,查到最后发现是数组越界导致的。数组只有30个字节,代码却向这个数组填充了35个数据,这个bug还是偶现的,查到它确实废了一番功夫。我就突然想到:C语言为什么不检查数组下标呢???先来个demo验证下#include<stdio.h>#include<stdlib.h>int main(){ int data[5]={0}; for(int i=0;i<8;++i) { printf("%d "原创 2022-05-25 22:08:30 · 435 阅读 · 1 评论 -
回调函数在命令解析中的应用
1、回调函数关于回调函数,在之前的文章《回调函数》已经详解讲解过了,这个文章不再讲解,不太懂的同学请看之前的文章《回调函数》。在之前讲解回调函数中就使用串口作为示例,使用回调函数可以方便封装通讯库,芯片/模块厂家的SDK和部分开源库经常这样做,这样可以实现模块间的解耦,模块化编程。这篇文章主要讲解回调函数在命令解析中的应用,一般命令中都会有功能码,用于区分这条命令到底执行的什么动作,命令字后面的数据的意义。在这种场景中,使用回调函数是一个不错的选择。2、经典写法在命令解析中,经典的写法使用s原创 2022-05-08 22:56:34 · 770 阅读 · 0 评论 -
回调函数
1、函数指针学习回调函数,其实就是函数指针的应用,关于函数指针在之前的文章《指针与函数》中有详细的讲解,这里不再展开详解,重新贴一下之前文章中函数指针的示例代码#include <stdio.h>void MyFun1(int x);void MyFun2(int x);void MyFun3(int x);typedef void (*FunType)(int); /* ②. 定义一个函数指针类型FunType,与①函数类型一致 */void CallMyFun(FunTy原创 2022-04-16 16:55:55 · 1315 阅读 · 1 评论 -
指针与函数
1、指针函数指针函数,从名字上看它本质上是一个函数。指针函数:返回值类型是指针的函数。函数声明如下:int *plusfunction(int a,int b);当然也可以写成如下格式:int* plusfunction(int a,int b);让指针标志 * 与int紧贴在一起,而与函数名f间隔开,这样看起来就明了些了,plusfunction是函数名,返回值类型是一个int类型的指针。指针函数就是一个普通的函数,普通到仅仅是因为它的函数返回值是指针而已。#includ原创 2022-04-10 08:50:47 · 1493 阅读 · 2 评论 -
指针与数组
1、定义指针:C语言中某种数据类型的数据存储的内存地址,例如:指向各种整型的指针或者指向某个结构体的指针。数组:若干个相同C语言数据类型的元素在连续内存中储存的一种形态。数组在编译时就已经被确定下来,而指针直到运行时才能被真正的确定到底指向何方。所以数组的这些身份(内存)一旦确定下来就不能轻易的改变了,它们(内存)会伴随数组一生;而指针则有很多的选择,在其一生他可以选择不同的生活方式,比如一个字符指针可以指向单个字符同时也可代表多个字符等。指针和数组在C语言中使用频率是很高的,在极个别情原创 2022-03-29 22:02:36 · 3946 阅读 · 1 评论 -
单片机中volatile的应用
01、简述一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。简单来说,如果这变量很重要,且你不想它被编译器优化,就用volatile修饰。02、用处关于编译器优化如果你在编译器器开了优化原创 2022-03-01 22:12:32 · 1430 阅读 · 2 评论 -
C语言中static关键字详解
C语言中staic关键字很简单,简单到你的任何一个项目中可以不写一个staic关键字也是没有问题的。写这篇章主要是一下自己的staic的理解和应用,当然在章开头依旧要照本宣科简述一下static关键字。1、简述static关键字在嵌入式C语言当中很简单,它有三个作用:作用一:在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。void test1(void){ unsigned char a; static unsigned char b;…...原创 2022-02-16 21:52:12 · 3624 阅读 · 0 评论 -
深入聊一下const关键字
const是一个C语言的关键字,它限定一个变量不允许被改变。使用const在一定程序上可以提高程序的健壮性,另外,在观看别人代码的时候,清晰理解const所起的作用,对理解别人的程序有所帮助。1、const简介下面简单描述一下const,基本都是教科书的知识。const修饰的变量,其值存放在只读数据段中,其值不能被改变。称为只读变量。关于什么是数据段,什么是代码段,请看我之前的文章《C语言的内存分配》。int const a;const int a;上面两条语句都可以将a声明为一个整数,原创 2022-02-08 21:27:18 · 1567 阅读 · 0 评论 -
联合体在单片机编程中的应用
1、联合体之前的文章《枚举和结构体的结合》文中提到,结构体就像是打包封装,把一些有共同特征的变量封装在内部。结构体是一种构造类型或复杂类型,它可以包含多个类型不同的成员。在C语言中,还有另外一种和结构体非常类似的语法,叫做联合体(Union)(有些地方也叫做共用体)。联合体举例如下union data{ char n; char ch; char f;};union data a, b, c;结构体和联合体的区别在于:结构体的各个成员会占用不同的内存,互相之间没原创 2022-01-27 22:07:46 · 2714 阅读 · 0 评论 -
关于结构体中指针的一些探讨
1、起因在上篇文章《STM32编程中枚举和结构体的结合》中,有读者对下列代码有疑问typedef struct{ char *name; //姓名 int num; //学号 int age; //年龄 float score; //成绩}stuff_s;stuff_s xiaoming;void xiaoming_inf_init(){ xiaoming.name = "xiaoming"; xiaoming.num = 1; xiaoming.age原创 2022-01-25 22:59:46 · 637 阅读 · 0 评论 -
STM32编程中枚举和结构体的结合
01、结构体定义基本定义:结构体,通俗讲就像是打包封装,把一些有共同特征(比如同属于某一类事物的属性,往往是某种业务相关属性的聚合)的变量封装在内部,通过一定方法访问修改内部变量。结构体的定义:第一种:只有结构体定义struct stuff{ char *name; //姓名 int num; //学号 int age; //年龄 float score; //成绩};第二种:附加该结构体类型的“结构体变量”的初始化的结构体定义,如下代码也就是定义结构体时原创 2022-01-08 14:37:55 · 779 阅读 · 0 评论 -
C语言在STM32中的内存分配
01、前言不说废话,先上示例代码uint8_t num_byte[4];uint32_t num_word;const uint32_t num_word_const = 0x1234;uint32_t *point_heap;int main(void){ uint8_t num_byte_stack; static uint8_t num_byte_static; point_heap = (uint32_t *)malloc(4); *point_heap =原创 2021-12-22 23:17:58 · 1390 阅读 · 0 评论 -
C语言的内存分配
01、ANSI C在ANSI C中数据类型包括:整形,浮点型,指针和聚合型(如数组和结构等)整形:字符,短整型,整型和长整型,他们都分别有有符号(singed)和无符号(unsingned)取值范围:没有带signed或者unsigned,默认signed长整型至少应该和整型一样长,而整型至少应该和短整型一样长在32位环境中,各种数据类型的长度一般如下:02、ARM C具体我们以IAR为编译器,版本7.2注意:在32位ARM中,字是32位,半字是16位原创 2021-12-17 23:46:04 · 2132 阅读 · 0 评论 -
C语言访问存储器的方法
在单片机中我们经常需要访问某个指定的寄存器或者到指定的RAM地址,在本文为简单描述,下文所说的存储器可指:寄存器,RAM等。01、宏定义:定义一个宏,将地址值转化为C指针,然后取这个指针指向的内容,这样就可以访问存储了,代码如下:#define SDA_DIR_REG *(__IO uint32_t *)SDA_MOD_OFFSET分析:(__IOuint32_t *)SDA_MOD_OFFSE 是强制类型转换强制转换为指针*(__IOuint32_t *)SDA_MOD_..原创 2021-10-22 21:03:17 · 2169 阅读 · 0 评论 -
链表在STM32中的应用
目录1、为何引入链表2、链表实现3、测试函数、为何引入链表在程序中经常面临一个问题,我们需要保存一定数量的对象,但是对象数目是不确定的,或者说是随时增加或减少的。这时候最简单的方法是创建一个足够大的数组,用来存储这些对象。我最近开发一个项目就遇到类似的问题,下面我把问题简化一下。需求:通过PC下发一些矩形的坐标和宽高信息,每个区域有个ID编号,并在这些矩形内填充一定的数据。通常情况下,最简单易懂的做法是,限制最多5个区域,每个区域存储1K数据。因此设置了这样的一个结构体(类似于面原创 2020-12-11 09:30:49 · 15215 阅读 · 5 评论 -
C语言关键字字节
和机器字长及编译器有关系:所以,int,long int,short int的宽度都可能随编译器而异。但有几条铁定的原则(ANSI/ISO制订的):1 sizeof(short int)2 sizeof(int)3 short int至少应为16位(2字节) 4 long int至少应为32位。 unsigned 是无符号的意思。 例如:16位编译器c原创 2016-08-07 21:22:24 · 1229 阅读 · 3 评论 -
大端小端详解
用C语言写程序时需要知道是大端模式还是小端模式。 所谓的大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;所谓的小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。 为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是原创 2016-08-22 21:00:28 · 978 阅读 · 0 评论 -
栈详解
1、栈概念 栈是一种具有后进先出性质的数据组织方式,也就是说后放进去的数据先取出,先放进去的数据后取出。栈底是第一个进栈的数据所处的位置,栈顶是最后一个进栈的数据所处的位置。2、满/空栈概念 根据SP指针指向的位置,栈可以分为满栈和空栈。 满栈:当堆栈指针SP总是指向最后压入堆栈的数据。 空栈:当堆原创 2016-09-03 19:36:47 · 2216 阅读 · 0 评论 -
字节对齐问题详解
1、解释字节(Byte)是计算机信息技术用于计量存储容量和传输容量的一种计量单位,一个字节等于8位二进制数,在UTF-8编码中,一个英文字符等于一个字节。字节按照一定规则在空间上排列就是字节对齐。现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据按照一定的规则在原创 2016-07-22 00:05:33 · 5831 阅读 · 0 评论 -
函数名与函数指针
一、通常的函数调用一个通常的函数调用的例子: /* 自行包含头文件 */ void MyFun(int x); /* 此处的声明也可写成:void MyFun(int) */ int main(int argc, char* argv[]) { MyFun(10); /* 这里是调用MyFun(10) 函数 */ return(0); }原创 2017-08-25 11:06:57 · 1134 阅读 · 0 评论 -
typedef的用法
基本定义: typedef为C语言的关键字,作用是为一种数据类型定义一个新名字。这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等)。 在编程中使用typedef目的一般有两个,一个是给变量一个易记且意义明确的新名字,另一个是简化一些比较复杂的类型声明。 用途一:与#define的区别 typedef 行为有点像 #define 宏,用其实际类原创 2017-08-23 12:57:44 · 1964 阅读 · 0 评论 -
指针数组和数组指针
一、指针数组和数组指针的内存布局 指针数组:首先它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身决定。它是"储存指针的数组"的简称。 数组指针:首先它是一个指针,它指向一个数组。在32 位系统下永远是占4 个字节,至于它指向的数组占多少字节,不知道。它是"指向数组的指针"的简称。 下面到底哪个是数组指针,哪个是指针数组呢: A) int *p1[10]原创 2017-09-02 16:55:15 · 1037 阅读 · 0 评论 -
指针函数和函数指针
1.指针函数 先看下面的函数声明,注意,此函数有返回值,返回值为int *,即返回值是指针类型的。 int *f(int a, int b); 上面的函数声明又可以写成如下形式: int* f(int a, int b); 让指针标志 * 与int紧贴在一起,而与函数名f间隔开,这样看起来就明了些了,f是函数名,返回值类型是一个int类型的指针。 首先它是一个函原创 2017-09-29 09:24:14 · 942 阅读 · 0 评论 -
C语言运算符优先级
每当想找哪个运算符优先级高时,很多时候总是想找的就没有,真让人气愤!现在,终于有个我个人觉得非常全的,分享给大家,欢迎拍砖!C语言运算符优先级优先级运算符名称或含义使用形式结合方向说明1[]数组下标数组名[常量表达式]左到右--()圆括号(表达式)/函数名(形参表)--.成员选择(对象)对象.成员名--->成员选择(指针)对象指针->成员名-- 2-负号运算符-表达式右到左单目运算符~...转载 2018-03-28 21:04:46 · 937 阅读 · 0 评论 -
C语言结构体
基本定义:结构体,通俗讲就像是打包封装,把一些有共同特征(比如同属于某一类事物的属性,往往是某种业务相关属性的聚合)的变量封装在内部,通过一定方法访问修改内部变量。结构体定义:第一种:只有结构体定义structstuff{charjob[20];intage;floatheight;};第二种:附加该结构体类型的“结构体变...原创 2018-05-29 15:21:55 · 1760 阅读 · 0 评论 -
BCD码详解
1、BCD码的种类BCD码可分为有权码和无权码两类:有权BCD码有8421码、2421码、5421码,其中8421码是最常用的;无权BCD码有余3码、格雷码等。1. 8421 BCD码8421 BCD码是最基本和最常用的BCD码,它和四位自然二进制码相似,各位的权值为8、4、2、1,故称为有权BCD码。和四位自然二进制码不同的是,它只选用了四位二进制码中前10组代码,即用00原创 2016-07-15 23:13:56 · 27341 阅读 · 0 评论