社区导航

 
快捷导航
  • 首页
  • 论坛
  • 查看新帖
  • 最新回复
  • 社区活动
  • 联系管理员
  • 消灭零回复
  • E金币兑换
  • 干货
搜索
查看: 955|回复: 18

[原创] C标准库有多大?

[复制链接]

7674

TA的帖子

54

TA的资源

版主

Rank: 6Rank: 6

发表于 2018-3-4 16:10:25 | 显示全部楼层 |阅读模式
在 以前发过一个帖子
单片机/嵌入式脚本 博览会

今天我重新来看这个东西,然后忽然想起以前没有考虑好的一个问题:

不管是以前的 tcc 还是别的任何东西,编译器也罢,正式的脚本语言也好。
假如真的要实现我最初所设想的那种。

用文本,不需要使用编译工具链就可以完成 功能的改写,那有一个很根本的东西。
就是说你要提供多少API给用户调用?

别的不说,至少C标准库要给出来吧?
那么好了,一个C标准库如果全用上,会占多大体积?

因为,是这样的,除非是边运行边编译(新)的脚本代码,否则,C标准库无论是以静态还是动态被链接,它必须存在于
MCU固件本身。
如果是这样子,那这个C标准库的HEX体积本身就很重要。

假如它很小,那没太大问题,假如它本身就几十K甚至几百K,那就完蛋了。
于是我测试了一下。

我没有一下子全部测试完毕,我以我自己的使用频率,挑选了15个标准库里,我最常用的4个库。
而且我只测试了若干个函数而已。
结果它所占的体积之大,让我震惊。
此帖出自编程基础论坛
没有一件事情是容易的,所以,起念头时,一定要好好琢磨


回复

使用道具 举报

7674

TA的帖子

54

TA的资源

版主

Rank: 6Rank: 6

 楼主| 发表于 2018-3-4 16:10:45 | 显示全部楼层

  1. #include <string.h>
  2. #include <time.h>

  3. /*
  4.     start
  5.     lib_time:
  6.     3 278 bytes of readonly  code memory
  7.        30 bytes of readonly  data memory
  8.     8 200 bytes of readwrite data memory
  9. */
  10. static void lib_time(void)
  11. {
  12.     struct tm t;
  13.     asctime((const struct tm *)&t);     //6 530 - 3278 = 3 252
  14. }

  15. /*
  16.     start
  17.     lib_ctype:
  18.     3 278 bytes of readonly  code memory
  19.        30 bytes of readonly  data memory
  20.     8 200 bytes of readwrite data memory
  21. */
  22. static void lib_ctype(void)
  23. {
  24.     isalnum('c');       // 3314 - 3278 = 36
  25. }

  26. /*
  27.     start
  28.     lib_string:
  29.     3 270 bytes of readonly  code memory
  30.        30 bytes of readonly  data memory
  31.     8 200 bytes of readwrite data memory
  32. */
  33. static void lib_math(void)
  34. {
  35.     //sin(0.3);                  // 5 574 - 3 270 = 2 304
  36.     acos(0.3);                 // 7 222 - 5 574 = 1 648   
  37. }

  38. /*
  39.     start
  40.     lib_string:
  41.     3 270 bytes of readonly  code memory
  42.        30 bytes of readonly  data memory
  43.     8 200 bytes of readwrite data memory
  44. */
  45. static void lib_string(void)
  46. {
  47.     char tmp[16];
  48.    
  49.     strcpy(tmp,"str");          // 3366 - 3270 = 96
  50.     strcat(tmp,"cat");          // 3406
  51.     memset(tmp,0,4);            // 3518
  52.     memcmp(tmp,"seet",4);       // 3634
  53.     memmove(tmp,"323",32);      // 3890
  54. }


  55. void c_standard_lib(void)
  56. {
  57.     //lib_string();
  58.     //lib_math();
  59.     lib_time();
  60. }
复制代码
没有一件事情是容易的,所以,起念头时,一定要好好琢磨


回复

使用道具 举报

7674

TA的帖子

54

TA的资源

版主

Rank: 6Rank: 6

 楼主| 发表于 2018-3-4 16:13:39 | 显示全部楼层
基本可以知道,除了 string.h 和 ctype.h这两个库相对较小。
尤其后者,单个函数甚至不超过50字节。

但time.h和 math.h却太大了。
可是这两个往往也是很重要的函数。
我没有去数这四个库分别有几个函数。

但几乎可以确认,如果全部编译出来,或者即使只选大部分高频次使用。
math.h编译出来至少在三四十K级别;
time.h 也不会少到哪去;

ctype.h大概在几K级别。
string.h应该在10K级别。

这样算下来,仅仅这四个库就已经占据了 上百K。
其实它已经比Lua的初始体积更大了。
没有一件事情是容易的,所以,起念头时,一定要好好琢磨


回复

使用道具 举报

7674

TA的帖子

54

TA的资源

版主

Rank: 6Rank: 6

 楼主| 发表于 2018-3-4 16:15:06 | 显示全部楼层
由此,我想起之前有人说过,在资源紧缺的mcu上,尝试让C标准库也被开放出来是没意义的。

当然,脚本却还是有意义的。
只是不要直接开放底层API,而是开放面对用户语境的API;

当然我也想起了 Ardunio,不得不说,它的选择和设计是正确而合适的。
没有一件事情是容易的,所以,起念头时,一定要好好琢磨


回复

使用道具 举报

168

TA的帖子

6

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2018-3-4 19:49:50 | 显示全部楼层
从来没有注意这个过,通常编译后不是只把有用的函数调用吗?

点评

是这样的。 平常我们编译下载运行的情况下。 整个过程是这样的。 自己写的程序,编译——要生成独立可执行文件或者MCU需要的机器码的时候,还经历了一个链接过程。链接过程就是把 所有涉及到引用的库(里面的  详情 回复 发表于 2018-3-4 23:36
同一个人想法  详情 回复 发表于 2018-3-4 21:07


回复

使用道具 举报

168

TA的帖子

6

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2018-3-4 20:11:18 | 显示全部楼层
在较小的mcu中一般只有少数或者没有API的吗?
“是这样的,除非是边运行边编译(新)的脚本代码,否则,C标准库无论是以静态还是动态被链接,它必须存在于
MCU固件本身。”在没有操作系统的mcu中,c库不是只有在编译时调用一次?而且在其编译成机器码后,不是只固定执行一些代码,没用的c函数不是直接不编译链接的吗?
来自一个初学者的疑问

点评

这里面有一个很大的问题是。 平时我们是在 电脑上编译,然后再把代码下载到MCU里运行。 但如果按照我的说法,是在运行过程中,使用脚本,那这个时候,这个MCU本身就会成为编译器。如果是编译器,你能不保留一份C  详情 回复 发表于 2018-3-4 23:38


回复

使用道具 举报

2118

TA的帖子

0

TA的资源

纯净的硅(高级)

Rank: 6Rank: 6

发表于 2018-3-4 21:07:40 | 显示全部楼层
lehuijie 发表于 2018-3-4 19:49
从来没有注意这个过,通常编译后不是只把有用的函数调用吗?

同一个人想法


回复

使用道具 举报

7674

TA的帖子

54

TA的资源

版主

Rank: 6Rank: 6

 楼主| 发表于 2018-3-4 23:36:55 | 显示全部楼层
lehuijie 发表于 2018-3-4 19:49
从来没有注意这个过,通常编译后不是只把有用的函数调用吗?

是这样的。
平常我们编译下载运行的情况下。

整个过程是这样的。

自己写的程序,编译——要生成独立可执行文件或者MCU需要的机器码的时候,还经历了一个链接过程。链接过程就是把 所有涉及到引用的库(里面的函数和其他定义) 包含进来。

举个例子,我在我自己写的main()函数里调用了printf,但我肯定没有自己实现printf,那么,它就会把C标准库里的实现给链接了过来,这个时候。你得到的HEX或者EXE将包含printf实现所对应的机器码。

好了,现在我是要在 MCU运行的过程里,实现调用。问题是,假如,假如我的MCU编译之时并没有在代码里调用过printf这个函数,我也没有链接时,把printf实现的机器码连接上去。
但是,我的MCU在运行中,我的脚本在被人使用时,假如此人正想调用printf.
那么,请问,MCU的脚本运行时,将上哪去寻找printf实现来调用?

所以,这个问题就是说,假如我想要在MCU运行中通过脚本开放给别人二次开发的能力,和足够的API,至少要包含部分的C标准库吧?
那么,开放给别人的C标准库接口,我的MCU固件里本身可能并没有全部调用,但是,为了在别人用脚本二次开发时调用,我就必须保证我把这些可能的接口实现,以一种形式,存放在这个MCU的固件里。
于是,按上述论述,只是15个C标准库里最常用的4个,就已经将近上百K。
这上百K的代码,在MCU初始编译时自然不是都被调用,但它们必须存在。

点评

恩,这样可以理解。这样方便是方便了,但是单片机的成本优势就没有,这样还不如使用高级的处理器来做。 或许可以这样进行修改: 1、对c库的函数像risc一样进行精简,去掉对嵌入式不适用的函数 2、在单片机的flash  详情 回复 发表于 2018-3-5 17:17
没有一件事情是容易的,所以,起念头时,一定要好好琢磨


回复

使用道具 举报

7674

TA的帖子

54

TA的资源

版主

Rank: 6Rank: 6

 楼主| 发表于 2018-3-4 23:38:54 | 显示全部楼层
lehuijie 发表于 2018-3-4 20:11
在较小的mcu中一般只有少数或者没有API的吗?
“是这样的,除非是边运行边编译(新)的脚本代码,否则,C ...

这里面有一个很大的问题是。
平时我们是在 电脑上编译,然后再把代码下载到MCU里运行。

但如果按照我的说法,是在运行过程中,使用脚本,那这个时候,这个MCU本身就会成为编译器。如果是编译器,你能不保留一份C标准库吗?
电脑上是有的,只是你从来不管因此从来没注意它的存在而已。
没有一件事情是容易的,所以,起念头时,一定要好好琢磨


回复

使用道具 举报

119

TA的帖子

0

TA的资源

一粒金砂(高级)

Rank: 3Rank: 3

发表于 2018-3-5 10:54:49 | 显示全部楼层
其实,我想了解下C标准库里的函数的实现代码,比如开平方等,用来参考,不知道去哪里找这样的文件,LZ知道吗?

点评

去gnu官方网站下载 glibc 源码。  详情 回复 发表于 2018-3-5 14:11


回复

使用道具 举报

7674

TA的帖子

54

TA的资源

版主

Rank: 6Rank: 6

 楼主| 发表于 2018-3-5 14:11:20 | 显示全部楼层
viphotman 发表于 2018-3-5 10:54
其实,我想了解下C标准库里的函数的实现代码,比如开平方等,用来参考,不知道去哪里找这样的文件,LZ知道 ...

去gnu官方网站下载 glibc 源码。
没有一件事情是容易的,所以,起念头时,一定要好好琢磨


回复

使用道具 举报

168

TA的帖子

6

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2018-3-5 17:17:47 | 显示全部楼层
辛昕 发表于 2018-3-4 23:36
是这样的。
平常我们编译下载运行的情况下。

整个过程是这样的。

自己写的程序,编译——要生成独 ...

恩,这样可以理解。这样方便是方便了,但是单片机的成本优势就没有,这样还不如使用高级的处理器来做。
或许可以这样进行修改:
1、对c库的函数像risc一样进行精简,去掉对嵌入式不适用的函数
2、在单片机的flash预留一定空间,通过上位机对所需函数进行导入,单片机调用(就像操作系统应用程序的安装一样),同时还能进行调试。
以上提供两点建议,不知可不可行,这是对方便与flash大小的妥协。

点评

不得不说,你的第二个办法,是个相当不错的思路  详情 回复 发表于 2018-4-14 01:58
嗯,所以其实最后我的选择是放弃这个思路。 直接开放写好的针对具体应用的少数 功能性API,就行了。  详情 回复 发表于 2018-3-5 18:18


回复

使用道具 举报

7674

TA的帖子

54

TA的资源

版主

Rank: 6Rank: 6

 楼主| 发表于 2018-3-5 18:18:11 | 显示全部楼层
lehuijie 发表于 2018-3-5 17:17
恩,这样可以理解。这样方便是方便了,但是单片机的成本优势就没有,这样还不如使用高级的处理器来做。
...

嗯,所以其实最后我的选择是放弃这个思路。
直接开放写好的针对具体应用的少数 功能性API,就行了。
没有一件事情是容易的,所以,起念头时,一定要好好琢磨


回复

使用道具 举报

13

TA的帖子

0

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2018-3-11 22:24:25 | 显示全部楼层
现在的MCU的存储空间越做越大,如果觉得存储空间不够用,为什么不能考虑换个MCU呢

点评

当然,只是考虑这种应用的限制而已。 做这种东西,自然是希望尽可能的适用咯  详情 回复 发表于 2018-3-13 10:51


回复

使用道具 举报

7674

TA的帖子

54

TA的资源

版主

Rank: 6Rank: 6

 楼主| 发表于 2018-3-13 10:51:45 | 显示全部楼层
wwzx2513 发表于 2018-3-11 22:24
现在的MCU的存储空间越做越大,如果觉得存储空间不够用,为什么不能考虑换个MCU呢

当然,只是考虑这种应用的限制而已。
做这种东西,自然是希望尽可能的适用咯
没有一件事情是容易的,所以,起念头时,一定要好好琢磨


回复

使用道具 举报

575

TA的帖子

1

TA的资源

纯净的硅(初级)

Rank: 4

发表于 2018-3-26 19:00:12 | 显示全部楼层
楼主,了解了解PicoC这个小型的C语言解释器。

点评

谢谢,是个很不错的选择~~  详情 回复 发表于 2018-3-28 10:56


回复

使用道具 举报

7674

TA的帖子

54

TA的资源

版主

Rank: 6Rank: 6

 楼主| 发表于 2018-3-28 10:56:50 | 显示全部楼层
mars4zhu 发表于 2018-3-26 19:00
楼主,了解了解PicoC这个小型的C语言解释器。

谢谢,是个很不错的选择~~
没有一件事情是容易的,所以,起念头时,一定要好好琢磨


回复

使用道具 举报

6

TA的帖子

1

TA的资源

一粒金砂(初级)

Rank: 1

发表于 2018-4-11 10:33:31 | 显示全部楼层
我也想知道


回复

使用道具 举报

7674

TA的帖子

54

TA的资源

版主

Rank: 6Rank: 6

 楼主| 发表于 2018-4-14 01:58:24 | 显示全部楼层
lehuijie 发表于 2018-3-5 17:17
恩,这样可以理解。这样方便是方便了,但是单片机的成本优势就没有,这样还不如使用高级的处理器来做。
...

不得不说,你的第二个办法,是个相当不错的思路
没有一件事情是容易的,所以,起念头时,一定要好好琢磨


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则