C语言----杂记

本文总结了嵌入式编程中常见的几个陷阱,包括常量溢出、数据范围溢出、宏定义与声明、数据进制错误、使用Null指针、char类型表示负数等问题,并给出了相应的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、常量溢出

u16  adc_temp = 0;   //应为: u32  adc_temp = 0;
for(i=0;i<100;i++)
{
    adc_temp += usADC_CS1[i];  //usADC_CS1[i]数组里面每个元素大于1000,导致adc_temp溢出
}
adc_temp /= 100;

1.2、数据范围溢出

将一个数拆分为N个随机数

 for(i=0;i<200;i++)
{
		buffer[i] = Random(); //申请一个随机数
		val -= buffer[i];     //当申请得到的 buffer[i] > val; 结果将溢出
		if(val<0x100)         
		{
				if(val)           //排除 val = 0;
				{
					buffer[i+1] = val;
				}
				break;
		}
}

可更正为:

 for(i=0;i<200;i++)
{
		if(val>255) //大于0xff分解
		{
				buffer[i] = Random();
				val -= buffer[i];
		}
		else        //小于或等于0xff直接记录并退出
		{
				buffer[i] = val;
				break;
		}
}

 

2、头文件中宏定义与声明

#ifndef __bsp_11_H
#define __bsp_11_H		

#include "stm32f10x.h"

#define  Data_CodeLine       140
//u8 Data_CodeLine = 140;   //宏定义Data_CodeLine 为140是可以的,但是当
                            //声明为u8类型的变量时,会报"多重定义"的错误

#endif

原因是当此头文件被不同C文件“Include”时,两个C文件都分别声明Data_CodeLine,导致多重定义。

采用宏定义可以避免此问题。

3、数据的进制

		  STMFLASH_Write(0x8019000,FlashBuff,10);
		  STMFLASH_Write(0x8019050,FlashBuff,10);
		
			 for(i=0;i<2;i++)
			STMFLASH_Read(0x8019000+i*50,FlashBuff,10);  //应为i*0x50

 

原本第二次想读取0x8019050开始,连续10个半字大小的地址的数据。但是“i*50‘这里错误,应为”i*0x50“。否则将导致从0x8019032这个地址开始读取。

 

4、避免使用Null指针

举个例子,编译环境为visual studio 2015:

int main() 
{
	int *p1, Num = 1;

	*p1 = Num;

	printf("*p1 = %d",*p1);

	getchar();
}

咋一看没问题,其实会报错:

这是因为,声明的指针“p1”,没有指向任一内存地址。在编译器里它默认指向“Null”,所以从逻辑上来说,对“p1”指向的内存地址取值,这本身不可取。但如果是MDK编译,是不会报错的,可见VS的编译器还是比较强大的。

延伸一下,链表的创建问题。

      链表的创建,一般是先声明链表结构体的指针变量,再通过“malloc(); ”申请链表结构体大小的内存空间,并将空间起始地址赋值给这个指针变量。然后便能通过指针变量,操作它指向的内存空间的数据。这里通过“malloc(); ”申请内存赋值给指针变量的过程,就相当于给指针指定一个内存地址,这样它就不会是一个指向“Null”的空指针了。

      除了使用“malloc(); ”,还有别的办法使链表结构体指针变量指向某一地址,完成链表的创建吗。有的,方法如下:

#include <stdio.h>
#include <math.h>


//创建链表结构体
typedef struct Node
{
	int Data;
	struct Node *Next;
}Node;

//声明链表结构体变量以及指针变量
Node  Head, Node1, Node2 ,Tail, *p4;

int main() 
{
	//给链表结构体变量成员赋值
	Head.Data = 3;
	Head.Next = &Node1;

	Node1.Data = 11;
	Node1.Next = &Node2;

	Node2.Data = 22;
	Node2.Next = &Tail;
	
	Tail.Data = 0;
	Tail.Next = 0;

	//头结点地址赋值给链表结构体指针变量p4
	p4 = &Head;
	printf("p4->Data = %d\r\n",p4->Data);

	p4 = p4->Next;
	printf("p4->Data = %d\r\n", p4->Data);

	p4 = p4->Next;
	printf("p4->Data = %d\r\n", p4->Data);

	p4 = p4->Next;
	printf("p4->Data = %d\r\n", p4->Data);

	getchar();
}

编译运行结果为:


声明链表结构体变量的时候,变量的地址已经由系统分配完毕。

p4 = &Head;

当链表结构体指针变量指向头结点时,我们便能通过操作指针变量来操作头结点。

p4 = p4->Next;

当它改为指向指针域时,因为头结点指针域指向Node1,所以此时它指向Node1。

由“malloc(); ”申请内存创建的链表存储在动态存储区,使用灵活可删除。

而这种方法创建的链表存储在静态存储区,无法删除链表释放Ram。

5、char类型表示负数

在MDK下运行以下代码:

int main(void)
{

        volatile char  a1 = -1;
	volatile short a2 = 100;
	volatile int   a3 = 250;
	
	
	a3 -= a2*a1;
	
	while(1);
}

进入仿真,查看变量的值:

然后将“a1”的类型“char”改为“short”,问题解决。

后面找到问题了,是MDK编译器将“char”类型默认为“unsigned char”类型,可在MDK中修改:

6、指针作为数组的应用

uint8_t *pBuf;

pBuf[0] = NRF24L01_RW(*pBuf++);
pBuf[1] = NRF24L01_RW(*pBuf++);
pBuf[2] = NRF24L01_RW(*pBuf++);
pBuf[3] = NRF24L01_RW(*pBuf++);
pBuf[4] = NRF24L01_RW(*pBuf++);	

 

原意是想,每发送一个数据,将发送缓冲数组中对应元素改为接收返回值。

但这里将指针当作数组使用出了问题。

分析  “pBuf[0] = NRF24L01_RW(*pBuf++);”

执行  1、“NRF24L01_RW(*pBuf);”

         2、“pBuf++;”

         3、 “pBuf[0]”等于 “NRF24L01_RW(*pBuf);”执行完毕的返回值

 

这里的问题是,“pBuf[0]”的地址是”pBuf“吗?

并不是的,因为第二步中,执行了“pBuf++;”,所以“pBuf[0]”的地址是”pBuf+1“

也就是说“pBuf[0]”变成了”“pBuf[1]“

 

7、"i++" 与 "++i" 的问题

int main() {

        int arr[] = { 3,4,5 }, *p1 = arr,y;

	y = *p1++ + (*(p1+++1)<<1);
	printf("%d\r\n",y);

	y = *p1;
	printf("%d\r\n", y);

	getchar();
}

以上程序输出结果:

11

5

第一个等式,“*(p1+++1)”,"++"优先级大于"+",先计算“(*p1+1)”,整个等式计算完毕后,p1再自增

由于第一个等式“p1”自增2次,所以第二个等式结果为5。

所以第一个等式等价于:y = arr[0] + (arr[1]<<1);

 

6、LKT4106加密芯片的坑

一个小小的加密芯片也能遇到很多坑。。。在这里慢慢填上

(1)

   u8  aa = 0x01, bb = 0xf4;
   u16 sum = 0;
		
   sum = ((aa<<8)|bb)/10;

   while(1)
  {

  }

上述代码“sum”结果应该是“0x01f4”,但是LKT4106运行出来变成了0xf4。解决办法是分开一步步运行,不要写在一起。。。

(2)

   unsigned char aa = 0x11, bb = 0x22;
   unsigned long sum = 0;

   sum  = aa;
   sum |= bb<<8;

   while(1)
  {

  }

理论上sum的值为“0x00002211”,实际上变成了“0xffff2211”.解决办法:

	 sum  = aa;
	 sum |= (bb<<8)&0x0000ffff;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值