|
▍很懒很操心 有一次,我在项目开发中想监控某段空间数据的大小,即这段空间在MCU中非常有限,希望每个版本在集成软件的时候都想获取其使用了多少空间,防止某些愣头青不珍惜内存,乱塞东西。而这段空间,我定义了一个神一样的结构体映射到这个空间,即其他开发人员只要在结构体增加元素即可(我使用洪荒之力将宏定义发挥到淋漓尽致才做到的,至于怎么实现的细节就不在这个文章讨论了,后续再写篇文章装装X)。. s0 e; N& n: u' u 计算这个结构体空间,要求:
总之,做这件事的目的是:每次集成的时候自动输出结果(很懒),也不行交给其他小伙伴去手工计算,或者更改原来的结构代码去计算这个空间,怕其乱来搞坏了原来的代码(很操心)。 再总之:能让电脑干的活,干嘛要让人去干! 于是,我就突发奇想,写个脚本呗。 那么啥子脚本可以计算C语言的结构体大小? 身为优秀的“嵌入式”工程师,对这种将C语言“嵌入”到脚本中的事情肯定是要研究一番的。 Note:为了方便描述,我将具体项目细节和装X的过程隐去,并将这个神一样的结构体简化为: typedef struct{ unsigned char item_a[2];3 _1 J+ D( ^ Q; l unsigned char item_b[3]; unsigned char item_c[5]; unsigned char item_d[8];4 z5 d4 r2 | I6 @8 K( r! G) Q 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的版本位数要跟GCC的对应,例如都选32位的。 方法1:Python调用exe方式 步骤:
接上代码看看 // struct.h, ]! q2 Y) y6 v; l2 M typedef struct {# Z, @+ x0 G. A2 ^6 M unsigned char item_a[2]; P! i+ N+ E/ w unsigned char item_b[3]; unsigned char item_c[5]; unsigned char item_d[8];0 s, f, ~; R9 O unsigned char item_e[33]; unsigned char item_fxxk[1];( @8 {; b- p1 p ^ unsigned char item_fxxxk[2]; unsigned char item_fxxk_any[55];' J: m9 S; G% V# O+ p% n# I8 E& _) P4 e }typeStructData; import os c_main = r''' n7 U6 o" L2 p+ `8 P #include <stdio.h>& V3 K! G- ~( g- U( z `) m3 j Z; _ #include "struct.h" int main(void)% I- k5 W5 N$ Q/ S& T" K1 G3 H$ } {9 H( g/ o4 [1 v, Z$ w. n, g ~ printf("size: %d\n", sizeof(typeStructData)); return 0; }9 a( v# d% j n# ]+ p1 T& v! J ''' def cal_struct_size(): G& {% K* B; S0 F; u: I f_c_main = 'xxxxsizeofstructxxxx.c'/ h2 A9 U& b( P0 p* ] f_run = 'xxxxsizeofstructxxxx.exe' with open(f_c_main, 'w') as f: f.write(c_main)" T; `# n0 w- E1 h5 l- O% n" M" _ gcc_compile = "gcc %s -o %s"%(f_c_main, f_run)4 m4 I: t+ e0 t5 [+ _" G5 _ : T% P% i0 \2 o+ i; I os.system(gcc_compile)1 b! _7 ]# v6 I: i# C# b j3 B os.system(f_run)9 \8 o( _" } a O# ` if os.path.exists(f_c_main): os.remove(f_c_main) if os.path.exists(f_run): os.remove(f_run)+ v% q+ V& u: e. i" w if __name__ == "__main__":, C2 y' }" `, ^% B; F6 Z cal_struct_size() 方法2:Python调用lib方式 总觉得用Python调用exe的方式有点low,再进一步,那就调用lib吧,例如调用.so内的函数或者变量。 步骤跟方法1类似:
Python调用lib库有个好处,可以调用其里面的具体函数等。 // struct.c#include <stdio.h> ! ~$ z1 j8 y$ Q G( j' q1 ` typedef struct { unsigned char item_a[2]; K# G6 L0 Y5 v* P* D unsigned char item_b[3]; unsigned char item_c[5];( D6 Z; \# @% d0 |6 S, d. L0 O7 v unsigned char item_d[8];4 D) } u. P' j9 N unsigned char item_e[33];- o' E8 j5 F- z unsigned char item_fxxk[1];) A6 o+ D, ~; d) d: Q unsigned char item_fxxxk[2]; unsigned char item_fxxk_any[55]; }typeStructData; s/ }* x1 {! E2 ^3 j0 g( s $ }* F8 Z8 M% T* r. B& N4 w int get_struct_size(void) { return sizeof(typeStructData); } import ctypes# C; K) f2 I7 t; j3 J# l import os 4 T D7 F( v& d% W0 O% o6 O6 v n os.system('gcc -shared -Wl,-soname,struct -o struct.so -fPIC struct.c') 2 [# a6 P! L! o4 j) n# G1 v struct_size = ctypes.cdll.LoadLibrary('./struct.so')! F4 o- i) t6 w1 a& c/ e0 t 5 Y+ A) Q$ S2 f; I& a& X def cal_struct_size(): s = struct_size.get_struct_size() print("size: %d"%s). F' K* e6 b# x! E4 ? if __name__ == "__main__":+ F5 c9 o9 k) }" g* f cal_struct_size()5 [7 s1 H/ t8 x' T5 ~ # if os.path.exists('struct.so'): os.remove('struct.so') 貌似有个小问题,如果想在脚本里面删除这个.so文件,会出现问题,因为没有办法unload这个.so。另外,关于这个话题,请参考:http://stackoverflow.com/questi ... ng-ctypes-in-python 方法3:Python调用C源码方式 调用exe和调用lib,都觉得很low,怎么办,能不能直接插入C源码呢? 那就用pyembedc吧,Python可以访问C的变量,C也可以访问Python的变量,是不是炫酷吊炸天。 例1,访问C内部变量 # callstruct_inline1.pyfrom pyembedc import C- t" J# Y! n+ ~ C9 @! C 5 T7 ~2 N* e4 t( h7 Z6 E! w struct_str = r'''& A& i5 Z1 H3 X" M typedef struct { B1 r( a, V4 E5 m7 t4 J unsigned char item_a[2];/ U' R/ g! D& R5 ]) b+ j/ | unsigned char item_b[3];% E+ t+ W) Y4 T/ A( s unsigned char item_c[5];1 e/ N) H7 d4 @' L$ A unsigned char item_d[8];1 z I" k! Z; ], l' i unsigned char item_e[33];. x# b4 w6 Z) C0 p) g unsigned char item_fxxk[1];- q0 P5 H ^) m* `" G8 ^ unsigned char item_fxxxk[2];' m/ s& }3 b ^1 ] unsigned char item_fxxk_any[55]; }typeStructData;9 \1 L1 Z- D1 p9 @9 @ struct_size = sizeof(typeStructData); ''' struct_size = 0 struct_f = C(struct_str) print('size: %d\n'%struct_size) 例2,访问C内部函数 # callstruct_inline2.py- E2 J$ D' X `# G, K: p: \4 |- B+ h3 \( z, ` from pyembedc import embed_c8 e! F4 ^; g. V( ^/ Z6 N struct_str2 = r''' typedef struct9 b3 m! \ Q5 V {* [& z9 K6 K( g6 e) x5 a3 p" S2 } unsigned char item_a[2]; unsigned char item_b[3]; unsigned char item_c[5];& G" K( U* P+ l" |& |" c+ m' A unsigned char item_d[8];5 o4 ^) `4 U* Y6 B$ q2 J' {) z unsigned char item_e[33]; unsigned char item_fxxk[1]; unsigned char item_fxxxk[2];9 w K9 ?+ D' `1 x unsigned char item_fxxk_any[55];& [0 F) Z/ d0 f0 D. Z; M }typeStructData; int get_struct_size(void) {0 R) G: w3 _% g return sizeof(typeStructData); }7 M# j6 K7 B4 {3 O. O8 s ''' 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
pyembedc.embed_c(string) -> cdllpyembedc.embed_c_precompile(string) -> cdll
▍将C/C++代码嵌入Ruby
能把C代码塞进Python,当然也能塞进Ruby。对于在Ruby上插入C源码,给大家安利一个库RubyInline。
RubyInline还有以下Features:
class MyTest inline do |builder|" M) P# [" f! e builder.c " long factorial(int max) {! P4 \( W1 k4 s6 G9 V( V4 g! j int i=max, result=1; while (i >= 2) { result *= i--; }0 A, r% X% |3 { f, [ return result; }"* H1 u) B6 a* `! b( U1 s end end t = MyTest.new() factorial_5 = t.factorial(5) require 'inline': e. x" D) d% l- f' p: @ class MyTest" o5 p; F7 y' X inline(:C) do |builder|4 z! b/ U* e5 ]$ D* y builder.include '<iostream>'. v3 q( z* ]5 i7 J builder.add_compile_flags '-x c++', '-lstdc++' builder.c ' void hello(int i) { while (i-- > 0) {) f$ M( M; m4 F! ^9 H- g0 w. f+ W std::cout << "hello" << std::endl;& u0 j# d. o; h6 ^1 N4 s$ d }$ F$ N' `. u8 F) F$ C3 z6 q' ] }' end end t = MyTest.new()) E/ P, c2 W6 v X( V# } t.hello(3) 是不是很好玩,是不是很想试试?但是我告诉你,我在Windows上没搞成功,但在Linux上搞起来了。应了网上某句话:想学Ruby,就用Linux吧,别在Windows上瞎折腾。话说回来,这个嵌入式C源码的用法,个人感觉Ruby的比Python的简洁直观。该用哪种方法,看实际需要吧。更多内容,详见:http://github.com/seattlerb/rubyinline ▍总结 想将C/C++塞进脚本,需要借助GCC,它才是让你装逼让你飞的前提条件。 |
微信公众号
手机版