别踩static的地雷

Winform项目Native AOT迁移实战:启动性能提升7倍的踩坑指南 Native AOT(Ahead-Of-Time)编译是.NET平台的一项关键技术,它通过将中间语言(IL)预先编译为原生机器码,从根本上改变了应用的执行模式。其核心原理在于消除JIT(即时编译)的运行时开销,实现近乎瞬时的启动速度,同时减少内存占用和依赖项。这项技术的工程价值在于为需要快速启动、独立部署的桌面应用和工具提供了新的优化路径,特别适用于频繁启用的监控工具、配置软件等场景。在实际应用中,开发者常会遇到第三方库兼容性、资源管理和动态编程模式等挑战。本文基于一个真实的数据采集与监控工具(TDS)迁移 阅读详情
  只要做过项目的朋友对关键字static应该都有一些了解,但未见了解很全面的。在C语言中,关键字static有以下明显的作用:1.static变量分配到静态内存中,这一点和全局非静态变量相同。
2.在函数体,static变量只要不进行修改操作,在被调用过程中其值将保持不变。
3.在模块内,全局static变量可以被模块内所有函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量,具有私有特点。
4.在模块内,一个static函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用,也具有私有特点。
   如果我们能够很好地利用static的这些特性,书写高内聚低耦合,更具模块化的代码就不会显得象句口号;如果不能很好地理解和使用它,一切都只是空谈。下面来举个例子来说明static在实际应用可能会遇到问题。
  如果要求实现下面的接口:为每个大小约1600字节的音视频裸数据(audio/video)添加包头(packet header),然后将打过包头的整个数据包发送到网络。打过包头的数据包格式如下:
                     <------packet----->
                     | header | data |
 
  我想有人可能会这么做:
 
#define MAX_PACKET_SIZE 1600
 
typedef struct _header
{
  bool type;  /*数据包类型*/
  bool length; /*数据包类型*/
 ...
}header;
 
bool send(bool type,uint8* data,uint32 length)
{
  uint8 packet[MAX_PACKET_SIZE+sizeof(header)]={0};/*定义数组*/
  header* pheader=(header*)packet;
 
  if(NULL==data || length<1)
  {
    return FALSE;
  }
 
 /*设置包头*/
  pheader->type=type;
  pheader->length=length;
 
  pheader++;
  memcpy((uint8*)pheader,data,length);/*拷贝数据到包头之后*/
  netSend(packet);/*将包发送到网络*/
  return TRUE;
}
  
  对于上面的代码,有人可能会有这样的疑虑,发送数据包到网络是一个非常频繁的操作,所以在send函数中,频繁地为packet分配栈内存是一种低效的做法。他可能会将上的代码修改为:
bool send(bool type,uint8* data,uint32 length)
{
  uint8* packet=NULL;
  header* pheader=NULL;
 
  if(NULL==data || length<1)
  {
    return FALSE;
  }
 
  packet= (uint8*)malloc(length+sizeof(header));
 
  if(NULL==packet)
  {
    return FALSE;
  }
 
  pheader=(header*)packet;
  pheader->type=type;
  pheader->length=length;
  pheader++;
 
  memcpy((uint8*)pheader,data,length);
 
  net_send(packet);/*将包发送到网络*/
 
  free(packet);
  packet=NULL;
 
  return TRUE;
}
 
使用动态内存好象可以解决上面的问题,但它没有考虑到频繁地使用malloc-free会产生大量的内存碎片。在嵌入式系统环境中,一般内存大小有限,所以这种做法最终会导致分配失败。对于处理大流量数据问题,一种比较常用的高效方法就是在函数内部使用静态数组(全局静态数组在这个应用中不建议使用,因为全局变量会增加函数间的耦合度)。嘿嘿,听到这样的建议,估计有人会马上这么改:
bool send(bool type,uint8* data,uint32 length)
{
  static uint8 packet[MAX_PACKET_SIZE+sizeof(header)]={0};
  header* pheader=(header*)packet;
 
  if(NULL==data || length<1)
  {
    return FALSE;
  }
 
  pheader->type=type;
  pheader->length=length;
  pheader++;
 
  memcpy((uint8*)pheader,data,length);
  net_send(packet);/*将包发送到网络*/
  memset(packet,0,sizeof(packet));/*清除本次内存操作*/
 
  return TRUE;
}
 
  朋友且慢,小心地雷!
 
  你是否忘了考虑代码可重入(reentrance)问题呢?这里使用packet静态数组的确不用频繁地分配动态或栈内存,但同时引入了代码不可重入的问题。因为函数内的static变量分配在静态内存区,供所有对象共用。在多任务系统中,如果有一个以上的任务同时访问该内存,很可能会出现问题。所以我们必须要用其它手段来消除这个不可重入问题。使用信号量semaphore是一个很好解决不可重入问题的方法。在上面代码中加入信号量:
bool send(bool type,uint8* data,uint32 length)
{
  static uint8 packet[MAX_PACKET_SIZE+sizeof(header)]={0};
  header* pheader=(header*)packet;
 
  if(NULL==data || length<1)
  {
    return FALSE;
  }
 
  semTake(semaphore,WAIT_FOREVER);/*等待信号量*/
 
  pheader->type=type;
  pheader->length=length;
  pheader++;
 
  memcpy((uint8*)pheader,data,length);
  net_send(packet);/*将包发送到网络*/
  memset(packet,0,sizeof(packet));/*清除本次内存操作*/
 
  semGive(semaphore);/*释放信号量*/
 
  return TRUE;
}
 
好,现在终于解决这个问题了。在我们的视频会议系统中,曾经就在将数据发送到网络上
踩过这个地雷,修改这个bug也化了很大功夫。
 
Qt5.14.2静态编译踩坑记:从源码到独立EXE,我花了6小时总结的避坑清单 本文详细记录了Qt5.14.2静态编译的全过程,特别是使用32位MinGW时的关键避坑技巧。从环境配置、参数优化到编译技巧和体积压缩,作者分享了6小时实战中积累的宝贵经验,帮助开发者高效完成静态编译,生成独立EXE文件。 阅读详情

相关推荐

从PyTorch到安卓App:一个超分模型部署的完整踩坑实录(附SAFMN项目代码)

本文详细记录了将PyTorch超分模型部署到安卓App的完整过程,涵盖模型转换、安卓端C++集成、图像处理优化及性能调优等关键环节。特别针对ncnn框架的实战应用,分享了从ONNX到PNNX的转换技巧、JNI内存管理陷阱以及移动端特有的性能优化策略,为深度学习模型移动端部署提供实用指南。

weixin_42525328的博客 412

static函数局部变量的使用

#include &lt;stdio.h&gt; #include &lt;stdint.h&gt; #include &lt;string.h&gt; #include &lt;math.h&gt; #include &lt;stdlib.h&gt; void staticFun(void) {    static  uint8_t  data = 0;    data++;    data...

奋斗的菜鸟博客 4537

LabVIEW温度数据保存到Excel的3个常见坑,我猜你至少踩过一个

本文详细解析了LabVIEW温度数据保存到Excel时的3个常见陷阱:数据覆盖、文件命名和路径管理,并提供了实战解决方案。通过正确的写入模式选择、安全命名实践和智能路径管理,工程师可以避免数据丢失,确保温度采集数据的可靠存储与分析。

weixin_30535843的博客 438

uint8_t / uint16_t / uint32_t /uint64_t 是什么数据类型 - 大总结,看完全明白了

uint8_t / uint16_t / uint32_t /uint64_t  是什么数据类型 在nesc的代码中,你会看到很多你不认识的数据类型,比如uint8_t等。咋一看,好像是个新的数据类型,不过C语言(nesc是C的扩展)里面好像没有这种数据类型啊!怎么

kiddy19850221的专栏 37万+

FreeRTOS CLI移植踩坑实录:从源码获取到解决HardFault的完整避坑指南

本文详细记录了FreeRTOS CLI移植过程中的常见问题与解决方案,从源码获取到HardFault调试的全流程避坑指南。重点解析了HAL库串口驱动适配、内存安全防护及性能优化策略,帮助开发者高效完成命令行接口移植,避免系统崩溃和性能瓶颈。

weixin_30915951的博客 357

数据打包发送方法

只要做过项目的朋友对关键字static应该都有一些了解,但未见了解很全面的。在C语言中,关键字static有以下明显的作用:1.static变量分配到静态内存中,这一点和全局非静态变量相同。 2.在函数体,static变量只要不进行修改操作,在被调用过程中其值将保持不变。 3.在模块内,全局static变量可以被模块内所有函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量,具有私有特点。 4.在模块内,一个static函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用,也具有私有特点。 如果我们能够很好地利用static的这些特性,书写高内聚低耦合,更具模块化的代码就不会显得象句口号;如果不能很好地理解和使用它,一切都只是空谈。下面来举个例子来说明static在实际应用可能会遇到问题。

openmv串口打包发送数据

通过串口助手得到的数据是 2C 12 05 00 5b 而不是 2c 12 00 05 5b顺序是反的,需要在32端进行处理才可以得到真实数据,处理过程如下,使用3号串口接收openmv的数据,1号串口打印。这样num就是所发送的数据了。

qq_45486948的博客 2017

Centos7网络配置(设置固定ip)

刚安装完系统,有的人尤其没有勾选自动网络配置的情况下,是访问不了外网的,本机也连不通虚拟机。或者现在有的是动态ip,几次之后启动ip地址就变了,会导致其他软件或程序之前连接配置要重新更改,很麻烦,下面讲解一下如何配置网络,如何设置成固定ip。

个人笔记git:https://gitee.com/tlangp/note.git 8052

【C++基础】enum,union,uint8_t,static

它内部包含各种属性,但是所有属性共用一块内存,导致这些属性都是对同一个二进制数据的解读,其中往往只有一个属性的解读是有意义的。并且,后面写入的属性会覆盖前面的属性,这意味着同一块内存,可以先供某一个属性使用,然后再供另一个属性使用。这样做的最大好处是节省内存空间。这些类型的来源:这些数据类型中都带有_t, _t 表示这些数据类型是通过typedef定义的,而不是新的数据类型。也就是说,它们其实是我们已知的类型的别名。所以有时候使用 Enum 的目的,不是为了自定义一种数据类型,而是为了声明一组常量。

py今天刷题了吗 714

架构——异地多活成熟的架构模式

摘要: 本文系统介绍了三种异地多活架构模式:业务定制型、业务通用型和存储通用型。业务定制型针对核心业务定制化设计,复杂度低但扩展性差;业务通用型通过统一配套服务(流量调度、配置中心等)实现多业务兼容,适合业务量大但一致性要求不高的场景;存储通用型依托分布式一致性数据库(如OceanBase、TiDB)天然支持强一致性,适合金融等高要求场景,但对部署距离和成本有较高限制。文章对比了各模式的优缺点及适用场景,为不同业务需求下的架构选型提供了实践指导。

小志的博客 7084

STM32CubeMX定时器配置

因为只有当 CH2 处于 输入模式 时,硬件才能把这根脚送进滤波器(TI2FP2通道之前要滤波),再生成 TI2FP2 这条支路供 Slave-Mode 控制器使用,也就是说TI2FP2 并不是“独立存在”的,但在CubeMX配置时:如下图,我们只设置Slave Mode和TI1FP1,之后,CH1就自动配置为 Input Capture 了,下图发现,Channel1只能 Input Capture 或者Disable。哪来的主定时器和从定时器呢?把待测 PWM 的高电平当“门”,连接到ETR。

2402_89015641的博客 3181

assets static

static:打包的时候不会比编译,只是被拷贝到了dist下面的static文件夹,直接引用。assets:打包的时候,会被编译,被webpack打包进你的代码里。assets:一般来说,放属于该项目的资源文件。static:里面放一些第三方库的文件。动态图片的使用:必须使用require。

zhumizhumi的博客 923

ubuntu18.04安装xenomai3.1(百分百成功版)

ubuntu18.04安装xenomai3.1(百分百成功版),保姆级教学!!!

h542812556sdu的博客 2059

Java中的static和volatile

Java中的static和volatile 144 作者 F6 关注 2015.06.07 22:18* 字数 476 阅读 844评论 0喜欢 4 《Effective Java》的并发章节讲了一个线程通信问题的例子,非常好的说明了如何由于失误代码导致的线程间通信失败,没有保证一个线程的所作的修改可以被另一个线程获知,也就是活性失败和安全性失败。回头想想,这样的失误(或者根本就不是失误,而

ytuglt的博客 1748

腾讯会议视频过期了怎么办?亲测可用:用这个免费插件抢救你的会议录制与回放

本文提供了三种亲测有效的腾讯会议视频过期恢复方案,包括浏览器缓存提取、专业工具组合及预防性措施。特别推荐使用免费插件抢救过期会议录制与回放,帮助职场人解决重要视频资料丢失的难题。

weixin_33686714的博客 264

XMC1402调试实战:如何用20元的Jlink-OB搞定SWD连接(附DAVE 4.4.2配置)

本文详细介绍了如何使用成本仅20元的Jlink-OB调试器,成功连接并调试英飞凌XMC1402芯片的完整实战流程。内容涵盖从理解芯片启动模式、使用Memtool完成首次烧录与模式切换,到Jlink-OB驱动安装、连接验证,以及在DAVE 4.4.2中配置调试环境并解决常见问题的全步骤,为个人开发者提供了一套高性价比的SWD调试解决方案。

zz67890的博客 553

Paru 完整指南:5 分钟上手的 Arch Linux AUR 包管理教程

你想装的软件,`pacman -S` 说官方仓库里没有。去 AUR 找吧?得手动克隆 PKGBUILD、用 makepkg 编译、再一个个排查 AUR 上的依赖——折腾半小时,装个软件的兴致全没了。 Paru 就是为了解决这件事:一个用 Rust 写的 AUR 助手,让你用几乎和 pacman 一样的命令,把 AUR 里的软件直接装上。 它的价值集中在三点:命令行和 pacman 高度兼容,`

gitblog_00410的博客 407

c#算法(5)—最小二乘法(二次曲线拟合)

最小二乘法——二次曲线拟合

qq_34059233的博客 1659

C++类型转换深度解析:从static_cast到dynamic_cast的实战避坑指南

类型转换是编程语言中处理数据表示形式的基础机制,它允许在不同数据类型间进行值传递和操作。其核心原理在于内存布局的重新解释或值的重新计算,确保数据在不同类型上下文中的正确语义。在C++等强类型语言中,类型转换的技术价值在于平衡灵活性与安全性,既能实现底层系统编程的精细控制,又能通过编译期和运行时的检查避免常见错误。应用场景广泛,从简单的数值精度调整到复杂的多态对象处理,再到系统级的内存操作,都需要精确的类型转换策略。本文聚焦于C++中的四种命名强制转换(static_cast、dynamic_cast、con

weixin_33938733的博客 328

GStreamer —— 2.1、Windows搭建GStreamer环境,Qt加载GStreamer库后运行 - “教程1:Hello world!“(附:完整源码)

GStreamer —— 2、Windows搭建GStreamer环境,Qt加载GStreamer库后运行"教程1:Hello world!"

796

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

C基础,计算机中的数以及volatile限定修饰符,指针及其注意事项,external,static,Void *

在C语言中可以用volatile限定符修饰变量,就是告诉编译器,即使在编译时指定了优化选项,每次读这个变量仍然要老老实实从内存读取,每次写这个变量也仍然要老老实实写回内存,不能省略任何步骤。

hailushijie的专栏 1660

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

CDH6.3.2离线安装避坑实录:从环境配置到CM启动,我踩过的那些雷

本文详细记录了CDH6.3.2离线安装过程中的12个关键陷阱与解决方案,包括环境配置、离线仓库搭建、数据库设置等常见问题。特别针对网络隔离环境下的依赖问题和Parcel分发错误提供了实用技巧,帮助运维人员高效完成CDH集群部署。

weixin_33737134的博客 529

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

C++类型转换全解析:从隐式转换到四种强制转换的实战指南

类型转换是编程语言中处理不同数据类型间运算与赋值的基础机制,其核心原理在于内存表示与值域范围的适配。在强类型语言如C++中,理解类型转换对于保证程序正确性、避免数据丢失和未定义行为至关重要。从技术价值看,合理的类型转换能提升代码灵活性,但不当使用会引入隐蔽Bug。在应用场景上,无论是算术运算、内存操作还是面向对象编程,都离不开类型转换的参与。本文聚焦C++基础类型转换,深入剖析隐式转换的算术提升、符号处理等细节,并系统讲解static_cast、dynamic_cast、const_cast和reinter

weixin_30709061的博客 308

从零学做简易扫雷(win32-非MFC-C语言版)

简易扫雷(win32-非MFC-纯C语言版) 起因 因转专业前后课程不一样,所以现在大二要补大一的程序设计实践,老师要求要想得高分就必须从这里面选:***,***,。。。 因为我比较喜欢玩扫雷,于是就选了扫雷。又不甘心写纯黑的控制台程序,就打算借此机会深入一下win32编程。废话不多说,开搞! 成品展示 初始界面: 游戏中: 获胜: 失败: 流程图: 制(学)作(习)过程 (点击看大图)...

画船听雨眠 2594
上一篇: 爱在毕业前夕
下一篇: vxworks测试题及解答
embeddedsoft
博客等级 码龄20年 51粉丝 39原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值