当前位置:首页 > 公众号精选 > 嵌入式微处理器
[导读]▍很懒很操心 有一次,我在项目开发中想监控某段空间数据的大小,即这段空间在MCU中非常有限,希望每个版本在集成软件的时候都想获取其使用了多少空间,防止某些愣头青不珍惜内存,乱塞东西。而这段空间,我定义了一个神一样的结构体映射到这个空间,即其他开


很懒很操

有一次,我在项目开发中想监控某段空间数据的大小,即这段空间在MCU中非常有限,希望每个版本在集成软件的时候都想获取其使用了多少空间,防止某些愣头青不珍惜内存,乱塞东西。而这段空间,我定义了一个神一样的结构体映射到这个空间,即其他开发人员只要在结构体增加元素即可(我使用洪荒之力将宏定义发挥到淋漓尽致才做到的,至于怎么实现的细节就不在这个文章讨论了,后续再写篇文章装装X)。

计算这个结构体空间,要求:

  1. 在软件集成阶段就获得这个结构体大小,而不是MCU运行的时候;(自动执行)

  2. 计算这个结构体大小,不要增加删除原程序代码;(悄无声息)

  3. 方便集成工程师使用,不增加使用难度;(简单易用)

  4. 不因为人操作的原因,而导致计算结果不准确,即自动化执行输出结果。(无人为干扰)

总之,做这件事的目的是:每次集成的时候自动输出结果(很懒),也不行交给其他小伙伴去手工计算,或者更改原来的结构代码去计算这个空间,怕其乱来搞坏了原来的代码(很操心)。

再总之:能让电脑干的活,干嘛要让人去干!

于是,我就突发奇想,写个脚本呗。

那么啥子脚本可以计算C语言的结构体大小?

身为优秀的嵌入式”工程师,对这种将C语言“嵌入”到脚本中的事情肯定是要研究一番的。

Note:为了方便描述,我将具体项目细节和装X的过程隐去,并将这个神一样的结构体简化为:

 typedef struct
 {
     unsigned char item_a[2];
     unsigned char item_b[3];
     unsigned char item_c[5];
     unsigned char item_d[8];
     unsigned char item_e[33];
     unsigned char item_fxxk[1];
     unsigned char item_fxxxk[2];
     unsigned char item_fxxk_any[55];
     // add items here...
 }typeStructData;

将C/C++代码嵌入Python

人生苦短,我用Python

温馨提示,使用以下方法,请提前安装:

  1. Python
  2. GCC(例如Windows上的MinGW)
  3. 用pip安装pyembedc(pip install pyembedc

注意:Python的版本位数要跟GCC的对应,例如都选32位的。

方法1:Python调用exe方式

步骤:

  1. 在一个临时C文件里,编写临时main函数;

  2. 用GCC构建编译,生成exe;

  3. 通过脚本(此处选择Python)调用运行输出结果;

  4. 删除临时C文件和exe文件。

接上代码看看

 // struct.h
 
 typedef struct
 {
     unsigned char item_a[2];
     unsigned char item_b[3];
     unsigned char item_c[5];
     unsigned char item_d[8];
     unsigned char item_e[33];
     unsigned char item_fxxk[1];
     unsigned char item_fxxxk[2];
     unsigned char item_fxxk_any[55];
 }typeStructData;
 import os
 
 c_main = r'''
 #include <stdio.h>
 #include "struct.h"
 int main(void)
 {
    printf("size: %d\n", sizeof(typeStructData));
    return 0;
 }
 '''
 def cal_struct_size():
     f_c_main = 'xxxxsizeofstructxxxx.c'
     f_run = 'xxxxsizeofstructxxxx.exe'
     with open(f_c_main, 'w') as f: f.write(c_main)
     gcc_compile = "gcc %s -o %s"%(f_c_main, f_run)
 
     os.system(gcc_compile)
     os.system(f_run)
     if os.path.exists(f_c_main): os.remove(f_c_main)
     if os.path.exists(f_run): os.remove(f_run)
 
 if __name__ == "__main__":
     cal_struct_size()

方法2:Python调用lib方式

总觉得用Python调用exe的方式有点low,再进一步,那就调用lib吧,例如调用.so内的函数或者变量。

步骤跟方法1类似:

  1. 在一个临时C文件里,编写临时main函数;

  2. 用GCC构建编译,生成lib(.so);

  3. 通过Python调用运行输出结果;

  4. 删除临时C文件。

Python调用lib库有个好处,可以调用其里面的具体函数等

 // struct.c
 
 #include <stdio.h>
 
 typedef struct
 {
     unsigned char item_a[2];
     unsigned char item_b[3];
     unsigned char item_c[5];
     unsigned char item_d[8];
     unsigned char item_e[33];
     unsigned char item_fxxk[1];
     unsigned char item_fxxxk[2];
     unsigned char item_fxxk_any[55];
 }typeStructData;
 
 int get_struct_size(void)
 {
     return sizeof(typeStructData);
 }
 import ctypes
 import os
 
 os.system('gcc -shared -Wl,-soname,struct -o struct.so -fPIC struct.c')
 
 struct_size = ctypes.cdll.LoadLibrary('./struct.so')
 
 def cal_struct_size():
     s = struct_size.get_struct_size()
 
     print("size: %d"%s)
 
 if __name__ == "__main__":
     cal_struct_size()
     # if os.path.exists('struct.so'): os.remove('struct.so')

貌似有个小问题,如果想在脚本里面删除这个.so文件,会出现问题,因为没有办法unload这个.so。另外,关于这个话题,请参考:https://stackoverflow.com/questions/359498/how-can-i-unload-a-dll-using-ctypes-in-python

方法3:Python调用C源码方式

调用exe和调用lib,都觉得很low,怎么办,能不能直接插入C源码呢?

那就用pyembedc吧,Python可以访问C的变量,C也可以访问Python的变量,是不是炫酷吊炸天。

例1,访问C内部变量

 # callstruct_inline1.py
 
 from pyembedc import C
 
 struct_str = r'''
    typedef struct
    {
        unsigned char item_a[2];
        unsigned char item_b[3];
        unsigned char item_c[5];
        unsigned char item_d[8];
        unsigned char item_e[33];
        unsigned char item_fxxk[1];
        unsigned char item_fxxxk[2];
        unsigned char item_fxxk_any[55];
    }typeStructData;
    struct_size = sizeof(typeStructData);
 
 '''
 struct_size = 0
 struct_f = C(struct_str)
 print('size: %d\n'%struct_size)

例2,访问C内部函数

 # callstruct_inline2.py
 
 from pyembedc import embed_c
 
 struct_str2 = r'''
    typedef struct
    {
        unsigned char item_a[2];
        unsigned char item_b[3];
        unsigned char item_c[5];
        unsigned char item_d[8];
        unsigned char item_e[33];
        unsigned char item_fxxk[1];
        unsigned char item_fxxxk[2];
        unsigned char item_fxxk_any[55];
    }typeStructData;
     
    int get_struct_size(void)
    {
        return sizeof(typeStructData);
    }
 '''
 struct_c = embed_c(struct_str2)
 print('size: %d\n'%struct_c.get_struct_size())

实际上,以上的操作,也是这个库偷偷地调用了GCC来编译C代码的(只是不是显式让你看到而已),你不安装对应版本的GCC也是做不到的。

顺便说是,这个pyembedc有几个方式:

Functionspyembedc.C(string) -> intpyembedc.inline_c(string) -> intpyembedc.inline_c_precompile(string) -> int

These functions will compile string containing the C/C++ code or directives (see below) and then link dynamically and run the code.

string is C/C++ code that can be used within a function. It can contain any valid C/C++ expression that your compiler will support.

The C function will automatically provide references to all local Python variables for use in your code to read or write as if they were basic types or arrays.

The inline_c and inline_c_precompile fucntion will not provide references to local Python variables and thus is faster and consumes less memory.

pyembedc.embed_c(string) -> cdllpyembedc.embed_c_precompile(string) -> cdll

These functions are used to compile code but not execute immediately. They return a CDLL object (see the CDLL python module) that can be executed later.

更多内容,请见:https://github.com/ftrias/pyembedc


将C/C++代码嵌入Ruby

生活诗意,我用Ruby

能把C代码塞进Python,当然也能塞进Ruby。对于在Ruby上插入C源码,给大家安利一个库RubyInline。

Inline允许您在Ruby代码中编写外部代码。它会自动确定相关代码是否已更改,并仅在必要时进行构建。然后将扩展自动加载到定义扩展的类/模块中。您甚至可以编写额外的构建器,使您可以用任何语言编写Inline代码。使用Inline :: C作为Module,并在Module#inline中查找所需的API。

RubyInline还有以下Features:

  • 快速,轻松地内嵌在ruby脚本中的C或C ++代码。

  • 可扩展以与其他语言一起使用。

  • 红宝石和C基本类型之间的自动转换* char,unsigned,unsigned int,char *,int,long,unsigned long

  • inline_c_raw用于自动转换不充分时。

  • 仅当内联代码已更改时才重新编译。

  • 假装是安全的。

  • 仅需要标准的ruby库,无需下载其他内容。

 require "inline"
 class MyTest
     inline do |builder|
         builder.c "
            long factorial(int max) {
                int i=max, result=1;
                while (i >= 2) { result *= i--; }
                return result;
            }"
         end
 end
 t = MyTest.new()
 factorial_5 = t.factorial(5)
 require 'inline'
 class MyTest
     inline(:C) do |builder|
         builder.include '<iostream>'
         builder.add_compile_flags '-x c++', '-lstdc++'
         builder.c '
            void hello(int i) {
                while (i-- > 0) {
                    std::cout << "hello" << std::endl;
                }
            }'
     end
 end
 t = MyTest.new()
 t.hello(3)
 

是不是很好玩,是不是很想试试?但是我告诉你,我在Windows上没搞成功,但在Linux上搞起来了。应了网上某句话:想学Ruby,就用Linux吧,别在Windows上瞎折腾。话说回来,这个嵌入式C源码的用法,个人感觉Ruby的比Python的简洁直观。该用哪种方法,看实际需要吧。更多内容,详见:https://github.com/seattlerb/rubyinline


总结

想将C/C++塞进脚本,需要借助GCC,它才是让你装逼让你飞的前提条件。


本文授权转载自公众号“嵌入式软件实战派”,作者实战派师姐


-END-




推荐阅读



【01】嵌入式系统中常用的IIC与SPI,这两种通讯方式该怎么选?
【02】嵌入式必看:Linux内存管理那些事儿
【03】嵌入式项目是如何评估系统所需的RAM和ROM用量的?
【04】嵌入式和单片机不一样?那它们的区别在哪?
【05】嵌入式开发碰到无法解决的问题?编程的凹凸性有妙用!(附C代码


免责声明:整理文章为传播相关技术,版权归原作者所有,如有侵权,请联系删除

免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

嵌入式ARM

扫描二维码,关注更多精彩内容

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭