C语言代码零碎

c语言*零碎知识便签 这篇博客是写一写c语言学习过程中的一些零碎的知识,不定时更新!一部分原创,一部分转自一些博客,或者是摘抄书本上的讲解~,c语言知识本来就比较零碎,感觉就是捡漏一样。 1 引脚,又叫管脚,英文叫 Pin。就是从集成电路(芯片)内部电路引出与外围电路的接线,所有的引脚就构成了这块芯片的接口。引线末端的一段,通过软钎焊使这一段与印制板上的焊盘共同形成焊点。我们电脑的触摸鼠标就是运用了引脚。 2 ... 阅读详情

 

1.关于数据类型的选择

在单片机C语言编程中,能够使用char定义的变量,就不要使用int来定义;能够使用int定义的变量就不要用long int,能不使用float就不要使用float。

当然,在定义变量后不要超过变量的作用范围,如果超过变量的范围赋值,很多C编译器并不报错,但程序运行结果却错了,而且这样的错误很难发现。

个人习惯在一些不涉及字符字符串的不涉及复杂数学运算的代码中,尽量统一用unsigned char ,这样在衔接一些通信协议的时候使用比较方便。

2、关于运算强度的选择

(1)、查表/运算

个人习惯,尽量避免在自己的主循环里进行运算工作,尽可能先计算好了,再到循环里查表。例1 以常见的阶乘函数为例

旧代码:

long factorial(int i)
{
    if (i == 0)
      return 1;
    else
      return i * factorial(i - 1);
}

 

 

新代码:

static long factorial_table[] = {1, 1, 2, 6, 24, 120, 720 ……};
long factorial(int i)
{
    return factorial_table[i];
}

有时候表很大,就写一个init函数,在循环外临时生成表格,然后在循环中查表。这个在一些简单的数据转换代码中经常能用到。

(2)求余

a=a%8;

可以改为:

a=a&7;

位操作只需一个指令周期即可完成,%运算有的是调用子程序来完成,代码长,执行速度慢。通常,只要求是求2的n方的余数,都可使用位操作的方法来代替。

(3)平方

a=pow(a, 2.0);

可以改为:

a=a*a;

51系列一般都有内置硬件乘法器,乘法运算比求平方运算快得多。既使是在没有内置硬件乘法器的单片机中,乘法运算的子程序也比平方运算的子程序代码短,执行速度快。

 

 

如果是求3次方,如:

a=pow(a,3.0);

更改为:

a=a*a*a;

则效率的改善更明显。

(4)除法

a=a*4;
b=b/4;

可以改为:

a=a<<2;
b=b>>2;

如果需要乘以或除以2n,都可以用移位的方法代替。用移位的方法得到代码比调用乘除法子程序生成的代码效率高。

实际上,只要是乘以或除以一个整数,均可以用移位的方法得到结果,如:

a=a*9

可以改为(a=a*(8+1)):

a=(a<<3)+a

3、循环

(1)充分分解小的循环

要充分利用CPU的指令缓存,就要充分分解小的循环。特别是当循环体本身很小的时候,分解循环可以提高性能。

(2)提取公共部分

对于一些不需要循环变量参加运算的计算任务可以把它们放到循环外面。对于那些在循环中调用的函数,凡是没必要执行多次的操作通通提出来,放到一个init函数里,循环前调用。另外尽量减少喂食次数,没必要的话尽量不给它传参,需要循环变量的话让它自己建立一个静态循环变量自己累加,速度会快一点。

还有就是结构体访问,凡是在循环里对一个结构体的两个以上的元素执行了访问,就有必要建立中间变量了。

旧代码:

total = a->b->c[4]->aardvark + a->b->c[4]->baboon + a->b->c[4]->cheetah + a->b->c[4]->dog;

新代码:

struct animals * temp = a->b->c[4];
total = temp->aardvark + temp->baboon + temp->cheetah + temp->dog;

(3)while循环和do…while循环

用while循环时有以下两种循环形式:

unsigned int i;
i=0;
while (i<1000)
{
   i++;
   //用户程序
}

 

或:

unsigned int i;
i=1000;
do
{
   i--;
   //用户程序
}
while (i>0);

在这两种循环中,使用do…while循环编译后生成的代码的长度短于while循环。

(4)循环嵌套

把相关循环放到一个循环里,也会加快速度。

旧代码:

for (i = 0; i < MAX; i++)         
    for (j = 0; j < MAX; j++)
        a[i][j] = 0.0;
    for (i = 0; i < MAX; i++)        

        a[i][i] = 1.0;

 

 

 

 

新代码:

for (i = 0; i < MAX; i++)      

{
    for (j = 0; j < MAX; j++)
        a[i][j] = 0.0;
    a[i][i] = 1.0;      

 }

(5)Switch

当switch用比较链的方式转化时,编译器会产生if-else-if的嵌套代码,并按照顺序进行比较,匹配时就跳转到满足条件的语句执行。所以可以对case的值依照发生的可能性进行排序,把最有可能的放在第一位,这样可以提高性能。

当switch语句中的case标号很多时,为了减少比较的次数,明智的做法是把大switch语句转为嵌套switch语句。把发生频率高的case 标号放在一个switch语句中,并且是嵌套switch语句的最外层,发生相对频率相对低的case标号放在另一个switch语句中。比如,下面的程序段把相对发生频率低的情况放在缺省的case标号内。

 

 

 

 

 

 

 

pMsg=ReceiveMessage();
switch (pMsg->type)
{
      case FREQUENT_MSG1:
        handleFrequentMsg();
        break;
        。。。。。。
      default:                     //嵌套部分用来处理不经常发生的消息
        switch (pMsg->type)
        {
          case INFREQUENT_MSG1:
               handleInfrequentMsg1();
               break;
        。。。。。。
        }
}

 

 

 

 

 

 

(6)关于循环的性能

要提升循环的性能,可以减少不随循环变化的代码段。

for( i 。。。)
{
if( CONSTANT0 )
{
  DoWork0( i );// 假设这里不改变CONSTANT0的值
}
else
{
DoWork1( i );// 假设这里不改变CONSTANT0的值
}
}

 

 

 

 

 

 

 

 

 

推荐的代码:

if( CONSTANT0 )
{
for( i 。。。)
{
DoWork0( i );
}
}
else
{
for( i 。。。)
{
DoWork1( i );
}
}

如果已经知道if()的值,这样可以避免重复工作。虽然不好的代码中的分支可以简单地预测,但是由于推荐的代码在进入循环前分支已经确定,就可以减少对分支预测的依赖。

(7)无限循环

在编程中,我们常常需要用到无限循环,常用的两种方法是while (1)和for (;;)。如何选择?在编译的汇编过程可以看到,for (;;)指令少,不占用寄存器,而且没有判断、跳转,比while (1)好。

4、避免读写依赖

当数据保存到内存时存在读写依赖,即数据必须在正确写入后才能再次读取。在一段很长的又互相依赖的代码链中,避免读写依赖显得尤其重要。简单来说,引进一个可以保存在寄存器中的临时变量。这样可以有很大的性能提升。

不好的代码:

float x[VECLEN], y[VECLEN], z[VECLEN];
。。。。。。
for (unsigned int k = 1;k < VECLEN;k ++)
{
x[k] = x[k-1] + y[k];
}

for (k = 1;k <VECLEN;k++)
{
x[k] = z[k] * (y[k] - x[k-1]);
}

 

 

 

 

 

 

 

推荐的代码:

float x[VECLEN], y[VECLEN], z[VECLEN];
。。。。。。
float t(x[0]);
for (unsigned int k = 1;k < VECLEN;k ++)
{
t = t + y[k];
x[k] = t;
}
t = x[0];
for (k = 1;k <;VECLEN;k ++)
{
t = z[k] * (y[k] - t);
x[k] = t;
}

5、函数

(1)不定义不使用的返回值

函数定义并不知道函数返回值是否被使用,假如返回值从来不会被用到,应该使用void来明确声明函数不返回任何值。

(2)对函数的错误返回码要全面处理

一个函数能够提供一些指示错误发生的方法。这可以通过使用错误标记、特殊的返回数据或者其他手段,不管什么时候函数提供了这样的机制,调用程序应该在函数返回时立刻检查错误指示。

示例:

char fileHead[128];
ReadFileHead(fileName, fileHead, sizeof(fileHead)); // Bad: 未检查返回值

DealWithFileHead(fileHead, sizeof(fileHead));       // fileHead 可能无效

正确写法:

char fileHead[128];
ret = ReadFileHead(fileName, fileHead, sizeof(fileHead));
if (ret != OK) {                // Good: 确保 fileHead 被有效写入
    return ERROR;
}
DealWithFileHead(fileHead, sizeof(fileHead));       // 处理文件头

(3)把本地函数声明为static

如果一个函数只在实现它的文件中被使用,把它声明为static以强制使用内部连接。否则,默认的情况下会把函数定义为外部连接。这样可能会影响某些编译器的优化——比如,自动内联。

(4)优先使用返回值而不是输出参数

使用返回值而不是输出参数,可以提高可读性,并且通常提供相同或更好的性能。

函数名为 GetXxx、FindXxx 或直接名词作函数名的函数,直接返回对应对象,可读性更好。

6、使用嵌套的if结构

在if结构中如果要判断的并列条件较多,最好将它们拆分成多个if结构,然后嵌套在一起,这样可以避免无谓的判断。

7、头文件循环依赖

简单的程序,尽量避免头文件循环依赖,指 a.h 包含 b.h,b.h 包含 c.h,c.h 包含 a.h, 导致任何一个头文件修改,都导致所有包含了a.h/b.h/c.h的代码全部重新编译一遍。
而如果是单向依赖,如a.h包含b.h,b.h包含c.h,而c.h不包含任何头文件,则修改a.h不会导致包含了b.h/c.h的源代码重新编译。

8、引用外部函数接口、变量

建议通过包含头文件的方式使用其他模块或文件提供的接口。
通过 extern 声明的方式使用外部函数接口、变量,容易在外部接口改变时可能导致声明和定义不一致。
最大的危害是,这种隐式依赖,容易导致架构混乱。

不好的代码:
a.c 内容

extern int Foo(void);   // Bad: 通过 extern 的方式引用外部函数
void Bar(void)
{
    int i = Foo();  // 这里使用了外部接口 Foo
    ...
}

应该改为:
a.c 内容

#include "b.h"      // Good: 通过包含头文件的方式使用其他.c提供的接口
void Bar(void)
{
    int i = Foo();
    ...
}

b.h 内容

int Foo(void);

b.c内容

int Foo(void)
{
    // Do something
}

9、goto

goto语句会破坏程序的结构性,所以除非确实需要,最好不使用goto语句。使用时,也只允许跳转到本函数goto语句之后的语句。

goto语句通常用来实现函数单点返回。
同一个函数体内部存在大量相同的逻辑但又不方便封装成函数的情况下,譬如反复执行文件操作, 对文件操作失败以后的处理部分代码(譬如关闭文件句柄,释放动态申请的内存等等), 一般会放在该函数体的最后部分,在需要的地方就goto到那里,这样代码反而变得清晰简洁。实际也可以封装成函数或者封装成宏,但是这么做会让代码变得没那么直接明了。

示例:

// Good: 使用 goto 实现单点返回
int SomeInitFunc(void)
{
    void *p1;
    void *p2 = NULL;
    void *p3 = NULL;

    p1 = malloc(MEM_LEN);
    if (p1 == NULL) {
        goto EXIT;
    }

    p2 = malloc(MEM_LEN);
    if (p2 == NULL) {
        goto EXIT;
    }

    p3 = malloc(MEM_LEN);
    if (p3 == NULL) {
        goto EXIT;
    }

    DoSomething(p1, p2, p3);
    return 0;   // OK.

EXIT:
    if (p3 != NULL) {
        free(p3);
    }
    if (p2 != NULL) {
        free(p2);
    }
    if (p1 != NULL) {
        free(p1);
    }
    return -1;  // Failed!
}

 

 

First:各种零碎代码 立即下载

相关推荐

伪傻瓜式安装sql server2008【附带安装包】

安装各式各样的软件无疑是学习过程中…较…为烦躁的一部分 木有醋 但还是开始吧 为什么这是伪呢? 因为刚开始天真无邪的我真的是傻瓜式安装(迷之自信),结果就B了(打开配置管理器的瞬间….一片空白) BaiduCloud分享 红领巾在何方?? Link链接:https://pan.baidu.com/s/1NZCxP0Y27dBPrgHoRWLDyQ...

EuniBoom的博客 6万+

BUIW 范例中常用的goto跳转函数模式

goto语言已经很少在C语言中使用了,然而为了书写简便,BUIW应用使用了具有ERR_TRY()和ERR_CHECK_PTR()的函数模式,此模式隐含地使用了goto语句,此函数模式特点如下:1. 返回值为0时表示成功,其它为失败情况的枚举值2. 需要在函数内部定义临时变量int nErr;3. 具有ERR_CATCH: 的跳转标签4. ERR_TRY()包含的函数的返回值同样要求:返回值为0时是成功,其它为失败情况的枚举值5. 指针检查使用ERR_CHECK_PTR(pBuf);函数框架如下:// ret

strayedbird的专栏 782

随机变量序列 收敛 检验 matlab,利用MATLAB验证样条插值的收敛性

问题提出多项式插值是不收敛的,即插值的节点多,效果不一定就好。对样条函数插值又如何呢?理论上证明样条插值的收敛性是比较困难的,但通过本实验可以验证这一理论结果。.实验内容请按一定的规则分别选择等距或者非等距的插值节点,并不断增加插值节点的个数。考虑实验2.1中的函数或选择其他你有兴趣的函数。(中函数)。实验要求(1)随节点个数增加,比较被逼近函数和样条插值函数误差的变化情况。分析所得结果并与拉格朗...

weixin_30895121的博客 4735

返回值问题及goto问题

hello.c: #include int printchar(void) { printf("aa\n"); } int main() { int ret=0; ret = printchar(); printf("ret = %d\n", ret); return 0; } cc hello.c .

ychongx的专栏 1331

ADS基础教程24 - Gerber文件的导入

一、引言二、基本概念1.仿真文件下载2.仿真文件介绍二、导入步骤1.新建workspace2.选择Layout结构3.导入设计4.选择文件类型5.导入文件6.预览文件内容7.铜皮离散问题四、总结选择。通过本文章结束,可以了解ADS中如何将导入Gerber文件,并且对导入的铜皮进行合并。下一步就针对导入的文件进行层叠设置和编辑。END!}}END!

XZ_ZC的博客 3055

置顶必读(2) | 《YOLOv11实战:从入门到深度优化》目录导航篇(持续更新中)

🏆 本文收录于 《YOLOv11实战:从入门到深度优化》 专栏。 本专栏系统梳理并持续复现全网各类 YOLOv11 / YOLO系列改进方案与实战案例,目前已覆盖 分类、检测、分割、追踪、关键点、OBB 检测 等多个方向。 内容坚持 持续更新 + 深度拆解 + 工程落地导向,不仅讲“怎么改”,更讲“为什么这样改、如何真正落地到项目中”。

**My Coding Family** 11万+

浅谈break 、continue、return,goto四种语句的区别。

浅谈break 、continue、return三种语句的区别: break,continue,return这三个具有跳转功能的语句在c语言中经常被用到,近期身边有些小伙伴总是把它们的用法搞乱,在这里笔者给大家整理了一下自己对三个语句的理解,也算是自己加深一下印象吧。 1.break : 通常break语句总是与if语句联在一起,即满足条件时便跳出循环。当程序...

weixin_30621711的博客 1199

深入剖析 Hive 中 CASE WHEN 与 IF 函数的性能差异:解锁高效数据处理的关键

CASE WHEN 函数堪称 Hive 中条件判断的多面手,它具备两种强大的语法形式,以应对各种复杂的业务逻辑。简单 CASE 表达式这种形式适用于对某一列的值进行直接的条件匹配。其语法如下:END例如,我们有一个记录学生成绩的表CASE scoreELSE 'D'搜索 CASE 表达式当业务逻辑需要更灵活的条件判断时,搜索 CASE 表达式便派上用场。它的语法为:CASEENDCASEELSE 'D'

2401_83088008的博客 1125

单出口函数的实现方式(goto do while)

C语言的同学都知道C有个争议性很强的关键字goto

小楼一夜听春雨 1569

【数字IC/FPGA】低功耗设计

低功耗设计方法功耗的类型低功耗设计方法静态低功耗技术多阈值工艺方法电源门控方法体偏置动态低功耗技术多电压域(Multi-Voltage Domain)预计算门控时钟门级优化技术毛刺的消除逻辑级优化物理级优化控制输入向量低功耗Soc系统的动态管理动态电压及频率调节技术低功耗操作系统存储器功耗控制总结 功耗的类型 CMOS电路中的功耗由两部分构成,第一部分为负载电容充放电时引起的功耗,称为动态功耗,另一部分为漏电流引起的功耗,称为静态功耗。其中动态功耗包括翻转功耗和短路功耗。翻转功耗是数字电路中信号翻转时电容充

qq_40268672的博客 3072

C++(Qt)软件调试---gdb调试入门用法(12)

学习GDB可以帮助程序员更好地调试程序,找到程序中的错误和问题,提高程序的质量和稳定性。 在开发大型软件时,程序中可能存在许多错误和问题,这些问题可能会导致程序崩溃或者出现不可预期的行为。 使用GDB可以帮助程序员更快地找到这些问题,并且提供一些调试工具来帮助程序员更好地理解程序的行为。

mahuifa的博客 5555

零碎的代码笔记之C语言

##此篇笔记仅仅只是作为零散的知识点记录以及记录下自己在学习过程中遇见的一些问题并提供了解决方案 ####最近在用C语言写数组循环左移时出现了一个问题:用while循环输入字符进不去循环,以下是原题目和代码: 循环左移问题 题目内容: 设计分治算法实现将字符数组A[n]中所有元素循环左移k个位置,例如,对abcdefgh循环左移3位得到defghabc。 输入格式: 第一行为数组长度n 第二行为...

weixin_43889700的博客 219

线性自抗扰控制(LADRC)系统算法框图

NLADRC自抗扰控制从Simulink仿真到PLC控制实现_自抗扰控制器 simulink仿真-优快云博客本文介绍了如何将ADRC自抗扰控制算法从Simulink仿真应用到PLC控制中,包括Simulink框图、TD微分器模型、MATLAB函数的使用、SCL控制代码,以及非线性状态误差反馈控制率的实现。提供了详细的MATLAB仿真步骤和PLC源代码链接。ADRC自抗扰控制算法(含梯形图完整源代码和算法公式)_adrc算法-优快云博客。

RXXW_Dor的博客 1463

C语言代码知识点零碎01

说白了,就是如果是值传递,函数内部不管怎么修理形参,修理的都是实参之外的另外开辟的一块内存的值(我是这么理解的,实际是不是不确定,不过估计多半是)。如果是引用传递,就是虽然我形参是另外一片地区,但是你把地址给我了,我就能像操控提线木偶一样操控这个地址的值,所以就能通过这种方式改变你实参,哈哈哈哈哈!“因此,对于test和&test你应该这样理解,test是函数的首地址,它的类型是void (),&test表示一个指向函数test这个对象的地址,结构体名即类型名,定义一个指针指向该类型,其值为变量的地址。

qq_45344681的博客 172

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

二刷C语言之后,我总结了这75个核心技巧(四万字详解)

本文是作者回归的第二篇博客,全篇一共四万字,这篇博客是博主二刷C语言的心得与体会,包含了75个C语言常考的知识点以及对应的面试题,可以用来回忆与复习!希望对你有所帮助

铭哥不写bug的博客 1157

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

C 单向链表之静态链表

C 单向链表之静态链表 一、链表的作用:实现了内存零碎数据的有效组织 比如下面总共有十个字节的空间,用了5个字节。这时我们用malloc来申请5个字节的空间,由于没有连续的内存,申请会失败,然而用链表这种数据结构来组织数据,就可以解决这类问题。 二、静态链表的实现 静态链表虽然没有太大作用,但对动态链表的理解很有帮助。链表的头和尾都好说,关键是节点的定义,节点定义如下: typedef stru...

Bryan_QAQ的博客 439

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

lua源代码学习(一)lua的c api外围实现

工作后,整个人已经比較松懈了。尽管一直在看lua的源代码。可是一直是比較零碎的时间,没有系统的整理,所以还是收获不多。由于近期工作也不是非常忙了,就想整理下lua的源代码学习的笔记。加深下印象,并分享给大家。 先说下这系列bolg我会每周更新2-3篇,没有顺序的 这些文章都是自己的浅薄的理解。有什么错误,还...

weixin_30608503的博客 187

第一篇博客——代码的开始

代码人+1+1

gu___zhou的博客 118

【C语言】C语言零碎知识点

C语言零碎知识点(精华)

学了就忘是正常现象 2717

C语言零碎知识点之字符串数组

在C语言中字符串数组有两种表示方法。

二木成林 3万+

如何用C语言打造零碎片、超低延迟的内存池?答案在这里

掌握C语言实现简单内存池(memory pool)的方法,有效解决动态内存碎片与分配延迟问题。适用于高频分配场景,通过预分配固定大小内存块提升性能,实现高效、可控的内存管理。代码简洁易集成,值得收藏。

AlgoChat的博客 1044

C语言多文件编写简单的扫雷游戏

使用C语言编写扫雷游戏 1.多文件 多文件包含自己写的头文件,和两个源文件。 2.大概思路。 作为新手编写扫雷游戏,只能利用数组,循环编写一个不太完善的扫雷游戏,下边是我写扫雷游戏的大致思路。 1、首先需要画一个棋盘,需要创建两个二维字符类型数组且大小相同,一个显示给用户,一个隐藏起来。 2、在隐藏的棋盘里边需要设置雷的个数,我设计的棋盘大小是10*10的,有100 个元素,其中雷的个数是20个。 雷用字符‘1’,表示, 3、进行扫雷,输入自己的坐标,并进行判断。 如果输入坐标在隐藏的数组里对应的不是雷,我

mcboke的博客 255

C语言的一些零碎知识

写这篇博客的目的是加深记忆C语言的一些零碎知识,应付马上到来的实习生面试。 1.字节对齐 为了提高 CPU 的存储速度,编译器会对 struct 和 union的存储进行优化,即进行字节对齐。对于 struct 或 union 中的 struct 或者 union 来说,它们的字节对齐标准就是它的所有成员中字节数最大的数据的字节数。 下表是各个变量占用的字节数: char 1字节 ...

weixin_42237077的博客 204

c语言零碎的小东西

零碎的第一节,没有条理。

weixin_51912875的博客 788

C/C++ 语言 零碎知识点的总结(2)干货

  C/C++ 语言 零碎知识点的总结(2)   在大三的有限时间中对自己所遇到过的C/C++知识点做学习记录,以便在自己遗忘之时回顾。   若有朋友想了解其他知识点,传送门:C/C++ 语言 零碎知识点的总结 (1) # include<stdio.h> int main( int argc,char *argv[] ) { printf("%d",(unsigned char)-1); return 0; } ...

~晨曦静竹~的博客 4365
上一篇: 十大经典排序算法(动态演示+代码),亲测有用
下一篇: JZ2440.jflash配置
菜鸟高工
博客等级 码龄16年 27粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

菜鸟高工

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

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

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

打赏作者

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

抵扣说明:

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

余额充值