精华内容
下载资源
问答
  • 60行C代码实现一个shell

    万次阅读 多人点赞 2019-09-15 00:16:19
    继300来行代码带你实现一个能跑的最小Linux文件系统之后,我们来看看如何60行C代码实现一个shell!在实现它之前,先看看这样做的意义。美是有目共睹的。Unix...
        

    继 300来行代码带你实现一个能跑的最小Linux文件系统 之后,我们来看看如何60行C代码实现一个shell!

    在实现它之前,先看看这样做的意义。

    美是有目共睹的。Unix之美,稍微体会,便能得到。

    1969年,Unix初始,没有fork,没有exec,没有pipe,没有 “一切皆文件” ,但是那时它已经是Unix了。它简单,可塑。

    Melvin Conway在1963年的论文中叙述fork思想时就解释说并行路径要用结果来交互,也就是在汇合的join点来同步结果。这个同步点所得到的,就是一个并行进程的 输出 。

    在此之外,Unix还有另一个原则,就是 组合小程序!

    Unix把一系列功能单一的小程序组合成一个复杂的逻辑,这个原则有以下优势:

    • 每一个小程序都很容易编写。

    • 每一个小程序可以分别完成。

    • 每一个小程序可以分别迭代修复。

    • 多个小程序可以自由组合。

    这是典型的模块化思想,小到统筹佐餐烧饭,大到组成生命的嘌呤嘧啶,都不自觉地和这种模块化思想相契机,原来这就是真理。 程序尽量小,只做一件事并且做好它。

    Unix程序在自身的逻辑之外对外暴露的只有输入和输出。那么 用输出连接另一个程序输入 就是一种好的方法。所谓Conway的join点对于Unix进程指的就是输出。

    对外暴露的越少,程序越内聚。这是一种范式,类似RISC处理器也是抽象出仅有的load和store来和内存交互。

    简单来讲,Unix程序通过输入和输出来彼此连接。下面是一幅来自Wiki的图示:640?wx_fmt=png

    Unix的另一个原则,即著名的 “一切皆文件!” 连接输出和输入的那个管道在Unix中被实现为Pipe,显然,它也是文件,一个FIFO文件。

    说实话,协作几个小程序形成一个大逻辑的思想还是来自于Convey,在Convey的论文里,他称为 协程, Pile可以说是直接实现了 Convey协程 之间的交互。有关这段历史,请看:

    用Pipe连接作为输出和输入连接Unix进程可以做成什么事情呢?让我们去感受一个再熟悉不过的实例,即数学式子:

    640?wx_fmt=png

    我们把运算符加号,乘号,除号(暂不考虑括号,稍后解释为什么)这些看作是程序(事实上它们也真的是),那么类似数字3,5,7,6就是这些程序的输入了,这个式子最终需要一个输出,获得这个输出的过程如下:

    1. 数字3,5是加号程序的输入,3+5执行,它获得输出8.

    2. 第1步中的输出8连同数字7作为乘号程序的输入,8 × 7执行,获得输出56.

    3. 第2步中的输出56连同数字6作为除号的输入,…

    这个数学式子的求值过程和pipe连接的Unix程序组合获得最终结果的过程完全一致。

    如果你相信数学可以描述整个世界,那么Pipe连同Unix程序同样是描述这个世界的语言 。

    在数学领域,程序 就是所有的运算符,加号,减号,乘号,除号,乘方,开方,求和,积分,求导…它们无一例外, 只做一件事。

    在Unix看来也同样。它做的事情和下面的应该差不多,而且更多:640?wx_fmt=png

    // plus.c
    #include <stdio.h>
    int main(int argc, char **argv)
    {
    	int a, b;
    
    	a = atoi(argv[1]);
    	b = atoi(argv[2]);
    
    	a = a + b;
    	printf("%d\n", a);
    }
    

    同样,我们可以写出除法,直到偏导的程序。然后我们通过pipe就能将它们组合成任意的数学式子。

    现在谈谈Unix组合程序的具体写法,如果我们要化简薛定谔方程,我们应该如何用Unix命令写出与上述式子等价的组合程序命令行呢?我们无法像数学家手写那样随意使用括号,显然,计算机并不认识它。我们能够使用的只有两个符号:

    1. 代表具体Unix小程序的命令。

    2. Pipe符号"|"。

    换句话说,我们需要写出一个 链式组合表达式。 这时就要用到前缀表达式了。

    数学式子里的括号,其实它无关紧要,括号只是给人看的,它规定一些运算的优先级顺序,这叫 中缀表达式 ,一个中缀表达式可以轻松被转换为 前缀表达式,后缀表达式 ,从而消除括号。事实上,Unix的Pipe最初也面临过这样的问题,到底是中缀好呢,还是前/后缀好呢?

    我们现在使用的Unix/Linux命令,以cp举例:

    cp $in $out
    

    这是一个典型的前缀表达式,但是当pipe的发明者McIlroy最初引入pipe试图组合各个程序时,最初上面的命令行被建议成:

    $in cp $out
    

    就像我们的(3 + 5) × 8 一样。但是这非常不适合计算机处理的风格,计算机不得不首先扫描解析这个式子,试图:

    1. 理解 “括号括起来的要优先处理” 这句复杂的话;

    2. 区分哪些是输入,哪些是操作符…

    对于式子(3 + 5) × 的求值,计算机更适合用一种在简单规则下非常直接的方式去 顺序执行 求解,这就是前缀表达式的优势。

    × 8 +  35就是(3 + 5) × 的前缀表达式,可以看到,没有了括号。对于pipe组合程序而言,同样适用于这个原则。于是前缀命令成了pipe组合命令的首选,现如今,我们可以用:

    pro1 $stdin|pro2|pro3|pro4|...|proX $stdout
    

    轻松组合成任意复杂的逻辑。

    Pipe协同组合程序的Unix原则是一个创举,程序就是一个加工过滤器,它把一系列的输入经过自己的程序逻辑生成了一系列的输出,该输出又可以作为其它程序的输入。

    在Unix/Linux中,各种shell本身就实现了这样的功能,但是为了彻底理解这种处理方式的本质,只能自己写一个才行。来写一个微小的shell吧。

    再次看上面提到的Unix Pipe的处理序列:

    pro1 $stdin|pro2|pro3|pro4|...|proX $stdout
    

    如果让一个shell处理以上组合命令,要想代码量少,典型方案就是递归,然后用Pipe把这些递归调用过程给串起来,基本逻辑如下:

    int exec_cmd(CMD *cmd, PIPE pipe)
    {
        // 持续解析命令行,以pipe符号|分割每一个命令
        while (cmd->next) {
            PIPE pp = pipe_create();
            if (fork() > 0) {
                // 父进程递归解析下一个
                exec_cmd(cmd->next, pp);
                return 0;
            }
            // 子进程执行
            dup_in_out(pp);
            exec(cmd->cmdline);
        }
        if (fork() > 0) {
            wait_all_child();
            return 0;
        } else {
            dup_in_out(pp);
            exec(cmd->cmdline);
        }
    }
    

    按照上面的思路实现出来,大概60行左右代码就可以:

    // tinysh.c
    // gcc tinysh.c -o tinysh
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/wait.h>
    
    #define CMD_BUF_LEN	512
    char cmd[CMD_BUF_LEN] = {0};
    
    void fork_and_exec(char *cmd, int pin, int pout)
    {
        if (fork() == 0) {
            if (pin != -1) {
                dup2 (pin, 0);
                close(pin);
            }
            if (pout != -1) {
                dup2 (pout, 1);
                close(pout);
            }
            system(cmd);
            exit(0);
        }
    	if (pin != -1)
    		close(pin);
    	if (pout != -1)
    		close(pout);
    }
    
    int execute_cmd(char *cmd, int in)
    {
    	int status;
    	char *p = cmd;
    	int pipefd[2];
    
    	while (*p) {
    		switch (*p) {
    		case '|':
    			*p++ = 0;
    			pipe(pipefd);
    			fork_and_exec(cmd, in, pipefd[1]);
    			execute_cmd(p, pipefd[0]);
    			return 0;
    		default:
    			p++;
    		}
    	}
    	fork_and_exec(cmd, in, -1);
    	while(waitpid(-1, &status, WNOHANG) != -1);
    	return 0;
    }
    
    int main(int argc, char **argv)
    {
    	while (1) {
    		printf("tiny sh>>");
    		gets(cmd);
    		if (!strcmp(cmd, "q")) {
    			exit(0);
    		} else {
    			execute_cmd(cmd, -1);
    		}
    	}
    	return 0;
    }
    

    下面是执行tinysh的结果:

    [root@10 test]# ls -l
    总用量 28
    -rw-r--r-- 1 root root    0 9月   1 05:39 a
    -rwxr-xr-x 1 root root 9000 9月   1 05:38 a.out
    -rw-r--r-- 1 root root    0 9月   1 05:39 b
    -rw-r--r-- 1 root root    0 9月   1 05:39 c
    -rw-r--r-- 1 root root    0 9月   1 05:39 d
    -rw-r--r-- 1 root root    0 9月   1 05:39 e
    -rwxr-xr-x 1 root root 9000 9月   1 05:38 tinysh
    -rw-r--r-- 1 root root 1167 9月   1 05:38 tinysh.c
    [root@10 test]# ./tinysh
    tiny sh>>ls -l |wc -l
    9
    tiny sh>>cat /etc/inittab |grep init
    # inittab is no longer used when using systemd.
    tiny sh>>cat /etc/inittab |grep init|wc -l
    1
    tiny sh>>q
    [root@10 test]#
    

    递归解析的过程中fork/exec,一气呵成,这就是一个最简单shell实现。它可完成组合程序的执行并给出结果。

    这个tiny shell命令解析器的逻辑可以表示如下:640?wx_fmt=png

    640?wx_fmt=png

    的计算,我需要写表示四则混合运算符的Unix程序,首先看加号运算符程序,将上文中plus.c改成从标准输入读取加数即可:

    // plus.c
    // gcc plus.c -o plus
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char **argv)
    {
    	float a, b;
    
    	a = atof(argv[1]);
    	scanf("%f", &b);
    
    	b = b + a;
    	printf("%f\n", b);
    }
    

    再看减法运算符程序代码:

    // sub.c
    // gcc sub.c -o sub
    #include <stdio.h>
    #include <stdio.h>
    
    int main(int argc, char **argv)
    {
    	float a, b;
    
    	a = atof(argv[1]);
    	scanf("%f", &b);
    
    	b = b - a;
    	printf("%f\n", b);
    }
    

    接下来是乘法和除法的代码:

    // times.c
    // gcc times.c -o times
    #include <stdio.h>
    #include <stdio.h>
    
    int main(int argc, char **argv)
    {
    	float a, b;
    
    	a = atof(argv[1]);
    	scanf("%f", &b);
    
    	b = b*a;
    	printf("%f\n", b);
    }
    
    // div.c
    // gcc div.c -o div
    #include <stdio.h>
    #include <stdio.h>
    
    int main(int argc, char **argv)
    {
    	int a, b;
    
    	a = atof(argv[1]);
    	scanf("%d", &b);
    
    	b = b/a;
    	printf("%d\n", b);
    }
    

    可以看到,这些都是非常简单的程序,但是任意组合它们便可以实现任意四则运算,我们看看640?wx_fmt=png这个如何组合。

    首先在标准的Linux bash中我们试一下:

    [root@10 test]# ./plus 5|./times 7|./sub 20|./div 6
    3
    6.000000
    [root@10 test]#
    

    计算结果显然是正确的。现在我在自己实现的tinysh中去做类似的事情:

    [root@10 test]# ./tinysh
    tiny sh>>./plus 5|./times 7|./sub 20|./div 6
    3
    6.000000
    tiny sh>>q
    [root@10 test]#
    

    可以看到,tinysh的行为和标准Linux bash的行为是一致的。

    简单吧,简单!无聊吧,无聊!Pipe连接了若干小程序,每一个小程序只做一件事。

    如果我们的系统中没有任何shell程序,比如我们没有bash,我们只有tinysh,加上以上这4个程序,一共5个程序,就可以完成任意算式的四则混合运算。

    现在我们用以上的组合Unix程序的方法试试计算下面的式子:

    640?wx_fmt=png

    根号怎么办?

    按照非Unix的编程风格,就要在程序里写函数计算开根号,但是用Unix的风格,则只需要再加个开根号的程序即可:

    // sqrt.c
    // gcc sqrt.c -lm -o sqrt
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    
    int main(int argc, char *argv[])
    {
    	float b;
    
    	scanf("%f", &b);
    
    	b = sqrt(b);
    	printf("%f\n", b);
    }
    

    有了这个开根号的程序,结合已经有的四则运算程序,让我们的tinysh用pipe将它们串起来,就成了。好了,现在让我们计算上面的式子:

    ./tinysh
    tiny sh>>./sqrt |./plus 3|./div 2
    9
    3.000000
    tiny sh>>q
    

    本文该结束了,后面要写的应该就是关于经典Unix IPC的内容了,是的,自从Pipe之后,Unix便开启了IPC,System V开始称为标准并持续引领着未来,但这是另一篇文章的话题了。

    最后,来自Unix初创者之一Dennis M. Ritchie关于Unix的满满回忆,非常感人:640?wx_fmt=pngThe Evolution of the Unix Time-sharing System :


    浙江温州皮鞋湿,下雨进水不会胖!

    (完)

    Linux阅码场原创精华文章汇总

    更多精彩,尽在"Linux阅码场",扫描下方二维码关注

    640?wx_fmt=png

    感谢您的耐心阅读,请随手转发一下或者点个“在看”吧~

    展开全文
  • 10余万行C代码开源之后,我被震惊了。。。

    万次阅读 多人点赞 2019-07-21 19:17:08
    7月12日,涛思团队对外宣布将研发了两年多的产品TDengine开源,10多万行C代码,包括最核心的存储引擎和计算引擎都上传到了GitHub上。上周末7月14日我写了一篇...

    712日,涛思团队对外宣布将研发了两年多的产品TDengine开源,10多万行C代码,包括最核心的存储引擎和计算引擎都上传到了GitHub上。上周末714日我写了一篇文章Hadoop快至少10倍的物联网大数据平台,我把它开源了》。一周时间,这篇文章的微信阅读量已经超过19万,留言超过560条。GitHub上,star数目超过5300fork数超过1300issue数超过135。官网taosdata.com流量暴涨,邮箱几天之内就是一千多封邮件,下载链接的邮件都无法发出,不得不购买腾讯的企业邮箱服务,不得不购买CDN服务。这个网络传播速度之快,远超我的想象。

    很多朋友戏称我是网红程序员,应该去发币,我只能哈哈大笑。殊不知,为这个开源,我们团队已经花了两年多时间,光我自己就贡献了3万多行代码,就更别说无数没日没夜的debug。我曾经连续两个月时间,每天至少12个小时,坐在笔记本前,一动不动。就在开源后,涛思数据整个团队在过去的一周每天14小时以上,回答各种网友提出的问题,还要迅速解决发现的一些BUG。币圈里,找到象我们这样的团队,估计难。

     

    微博、朋友圈里很多人不看我们详细文档,不下载源码,不测试,直接质疑,怎么可能会比Hadoop,比InfluxDB快那么多,Jeff就是一个标题党,会营销。殊不知,我们是为了好记,才说快10倍,其实远远不止10倍。幸好有热心网友,制作docker,让大家几乎不写代码就能测试10亿、100亿条记录的查询。团队的胜亮同学,花了至少三天时间,将InfluxDBTDengine的对比,一步一步的解释很清楚,而且公开整个测试代码、测试数据集和环境。国内有众多的实时数据库厂商,还有一批时序数据库厂商,都宣称性能超强,但至今还没有一个公开测试代码的,我希望起个头,大家都晒晒。

     

    TDengine之所以超强性能,是由于我认真分析过物联网大数据的特点,充分利用这些数据特点,从零开始,专门打造出的一个大数据平台。涛思数据团队在所有的场合,都强调,TDengine只能解决物联网、车联网、工业互联网、运维监测等场景的时序数据处理问题,不是一个通用大数据系统。如果我们这个专用的不比那些通用的大数据系统好上十倍,那我这个35年码龄的程序员的程序真是白写了。

     

    在开源之前,TDengine定位为“专业高效的时序空间大数据处理引擎”,团队一直觉得不够合适,太技术,让客户的决策者搞不懂。而且TDengine不只是一个时序数据库,它还有缓存、数据订阅、流式计算等功能。严格的来讲,它能处理所有结构化的日志数据,包括运营商的通话记录、上网记录、交通卡口记录、股票交易数据等等。但做公司,必须客户定位精准,有所放弃。因此我们决定采用“为物联网而生的大数据平台”这个定位。这个定位,让TDengine在物联网与大数据这个交叉的领域独占鳌头,因为市场上还找不到这样的产品。我们坚信,5年的时间,世界上90%的数据都将是物联网类型的数据,如果大家处理这些数据,想到的第一品牌就是TDengine,那我们独角兽的梦想应该不会落空。

    总有一些合作伙伴担心我们团队太小,因为我们到现在为止,全职的才整整9个人。但殊不知,我们这个团队是超级战队。9个人里面,5个是中国科大本科毕业,4位在美国留学过,还有两位是中国科大最高荣誉的郭沫若奖学金获得者。非中国科大系的,毕业于科学院计算所、清华和上海交大,整个团队就有三位博士。如果大家要找10倍程序员,涛思数据就有7位。我十分的幸运,凭自己的实力、激情和对未来的憧憬,吸引了我力所能及引进的最优人才。我宁愿慢下来,我也不会放弃对团队素质的要求,因为涛思数据是一定要面向全球市场,是一定要与国际一流的软件企业PK的。如果团队没有世界一流的水平,仅靠996和口号是无法取胜的。我更坚信,创业初期的团队更加重要,因为公司壮大后,每个人都将是带兵打仗的悍将。

     

    总有VC或根本不清楚底层软件开发难在何处的人说,TDengine没有什么技术含量,BAT、华为这样的公司一出手,就把它灭了。但他们不知道,象TDengine这样的底层软件,不是原理多难,算法多难,而是实现的工程难度大。这个难度大,不是靠人多、钱多解决的。如果靠人多能解决,源自中国的的操作系统和数据库早就引领全球。在2016年底决定启动TDengine时,我就意识到这个技术挑战相当之大,因此才下决心亲自操刀,毕竟我自己身经百战,踩过无数技术的坑,而且有相当的产品的经验,应该能写出一个具有超强竞争力的框架和核心出来。

     

    但项目启动后,我才发现TDengine的难度远远超出预期。因为想充分利用物联网数据的特点,所以没有依赖任何第三方软件,开发了内存管理、文件管理、消息队列、开发了自己的RPC。为了保证数据写入有足够的资源,不被耗时的数据分析抢占,只好写了自己的线程调度。担心各种原因导致数据写不进系统,又实现了客户端的流控。分布式计算查询设计的好好的,但最后发现,要KILL一个分布在多个节点的查询,复杂度相当之高,为防止在KILL后的各种资源泄露,只好实现了一整套的checkpoint

     

    客户端的driver实现也是难度极大,最开始的版本,我自己就重写了两遍。服务器的设计,一切操作都是异步的,都是事件或消息驱动的。但到了客户端,传统的SQL操作都是同步阻塞的操作,只能实现将异步专为同步的机制。为了高效,又提供一套异步的API,导致同步、异步纠缠在一起。再加上IP重定向,元数据缓存等等,整个问题变的极为复杂。团队的廖博士和洪泽,经常被客户端问题折腾。

     

    TDengine从设计的第一天起,就定位为一个分布式系统。分布式系统最难的是DEBUG,因为牵涉到多台服务器,每台服务器有多个模块。当你从应用插入100亿条记录,其中一条记录丢失,如何定位,如何找到原因?所幸的是,我十多年从事无线数据核心网络设备研发的经验帮了大忙。通讯设备,历来都是分布式的,都是可以热插拔的,是水平扩展的。通讯行业早有成套的方法论来解决这类问题,那就是日志。但日志怎么写,欢迎各位程序员去GitHub下载源码看看涛思数据团队是怎么写的。

     

    早几天,博主byongda想解读一段TDengine代码,我稍微思索一下,提出可以分析tsched.c。这段程序实现的是一个任务队列,同时带有线程池。因为这段程序是计算机操作系统里经典的consumer-producer (生产者-消费者)问题的实现。凡是真正学过操作系统这门课的,都应该知道这个问题。但遗憾的是,我2008年回国后,面试过数百人,到目前为止,还没有一个人在面试时,随手正确的写下这个问题的伪代码。曾有人面试还给我较真,他的程序就是对,但是我明确的告诉他,如果你不用两个semaphore (信号量),一个mutex (互斥量), 你的程序一定错,回去好好看书。我也相信,中国高校里教操作系统的老师,也没有几个能随手写出这段程序的。如果你能随手写下正确的这段程序,那么你就有资格开发底层软件了。否则,开发出成功的底层软件只是你的梦想。在美国,我的一些同事就能随手写出来,我想这就是中美软件开发的差别。

     

    开发TDengine是有真正的技术挑战,这样的挑战,让我在50岁的年龄,还乐意尝试一把,不为别的,就为“Leavea dent in the world”。如果你也乐意接受技术挑战,欢迎加入涛思数据,即便不加入,也欢迎做TDengine开源项目的contributor。如果你不写程序,但喜欢与我们这类程序员呆在一起,喜欢听程序员的故事,喜欢与程序员互动,那也欢迎加入涛思数据,我们正在组建开发者社区运营团队,需要你!

    无论如何,只要你保持对我们的关注,到GitHub上下载源码,测试体验,反馈意见,就是对我们开源的最大支持,中国底层软件突破就有希望。

     

    Together, we make difference!

     

    展开全文
  • 将matlab代码转换成C代码

    千次阅读 2018-11-29 22:47:15
    MATLAB Coder可以从MATLAB代码...1. 使用MATLAB Coder产生C代码的4个步骤: (1) 开发实现特定算法功能的MATLAB代码及其测试文件; (2) 检查MATLAB代码的兼容性,确保MATLAB代码中的语句都能被转换成C代码(有些matl...

    MATLAB Coder可以从MATLAB代码生成独立的、可读性强、可移植的C/C++代码。本文基于matlab2015a编制,但是也适用于matlab 2014~2016的版本

    1. 使用MATLAB Coder产生C代码的4个步骤:

    (1) 开发实现特定算法功能的MATLAB代码及其测试文件;

    (2) 检查MATLAB代码的兼容性确保MATLAB代码中的语句都能被转换成C代码(有些matlab代码语句并不能生成c/c++代码,例如matlab中的imreadimshow函数就不能被转换c代码);

    (3) 产生最终使用的源代码或MEX;

    (4) 利用MATLAB Coder生成c++代码,并在vs2008中验证

    2. Matlab功能模块代码及其测试代码

    2.1 foo.m

    function c = foo(a, b)%#codegen

    %This function muliplies a and b

    c = a.* b;

    2.2 foo_high.m

    其中,%#codegen可以防止出现警告错误

    function r1 = foo_high(v1, v2)%#codegen

    %This function muliplies a and b

    r1=zeros(1,3);

    r1(1)=foo(v1(1),v2(1));

    r1(2:3) = foo(v1(2:3),v2(2:3));

    2.3 test_main.m

    clear all

    clc

    close all

    a=8.97;

    b=1.786;

    a=[2.1 7.3 11];

    b=[1.9 3.3 8];

    rc = foo_high(a, b)

    2.4 results

    rc =3.9900 24.0900 88.0000

    3. matlab代码转成C代码的详细步骤

    (1) 在命令窗口,输入mex -setpu,选中一个存在的编译器;

    (2) 在命令窗口输入coder(图形界面),回车,弹出MATLAB Coder Project对话框;

    或在matlab软件的界面中点击MatLab Coder图标。

    生成的MATLAB Coder界面如下图所示:

    (3) Generate code for function中输入需要转换为C代码的matlab功能模块文件:foo.mfoo_high.m

    (4) 点击next按钮,进入Define Input Types界面。输入test_main.m测试文件

    (5) 点击Autodefine Input Types按钮,从而使得matlab能自动检测出foo函数的接口变量的维度和类型。

    (6) 点击next按钮,进入check for run-time issues界面

    点击check for issues按钮进入对应的界面:

    上述问题表示激活的代码没有调用foo函数的入口foo函数没有被调用。因为foo函数的功能已经被包含在foo_high函数中了。这里的红色部分可以不用理会。

    (7) 点击next按钮,进入Generate Code界面:

    点击“Generate”按钮matlab生成对应的C代码并显示对应的界面:

    (8) 点击next按钮,显示结束Finish Workflow”界面

    4. 在vs2013中对转换获得的C代码进行测试。

    Matlab转换生成的C代码,会生成一个codegen文件夹,下面包含两个子文件夹libmexLib子文件夹下面包含xxx.h/xxx.c/xxx_initialize.c/xxx_initialize.c/xxx_tpyes.h

    /rt_nonfinite.c/rt_nonfinite.h/rtGetInf.c/rtGetInf.h/rtGetNaN.c/rtGetNaN.h文件,其中只有xxx.c转换后所获得的核心文件。其它文件都是支持性文件。Mex文件夹下的文件是具有冗余的文件可不予考虑。

    4.1 foo_high.c

    void foo_high(const double v1[3],const double v2[3],double r1[3])

    {

    int i1;

    /* This function muliplies a and b */

    r1[0] = v1[0] * v2[0];

    /* This function muliplies a and b */

    for (i1 = 0; i1 < 2; i1++) {

    r1[1 + i1] = v1[1 + i1] * v2[1 + i1];

    }

    }

    4.2 Main.c

    #include <iostream>

    #include <D:\matlab_to_C\test_folder_5\vs_project2\foo_high.c>

    using namespace std;

    int main()

    {

    double a[3] = {4,9,2};

    double b[3] = {2,7,8};

    double c[3];

    //cin >> a >> b;

    foo_high(a,b,c);

    cout << "c = " << c << endl;

    cout << "c[0] = " << c[0] << endl;

    cout << "c[1] = " << c[1] << endl;

    cout << "c[2] = " << c[2] << endl;

    cin.get();

    return 0;

    }


    5. Example of C_Plus_Plus code

    5.1 func1

    #include <iostream>

    using namespace std;

    int func1(int a, int b)

    {

    int i0;

    i0 = a*b;

    cout << "\n***Good Test*******" << endl;

    //return(int)i0;

    return i0;

    }

    5.2 main

    #include <stdio.h>

    #include <iostream>

    extern int func1(int a, int b);

    //#include"func1.cpp"

    using namespace std;

    int main(void){

    int i, a[10];

    int b[8] = {11,22,33,44,55,66,77,88};

    cout << "*****Good Test*******" << endl;

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

    a[i] = i;

    for (i = 9; i >= 0; i--)

    printf("%d ", a[i]);

    for (i = 7; i >= 0; i--)

    printf("%d ", b[i]);

    int rt;

    rt = func1(8, 9);

    cout << "rt="<< rt << endl;;

    cin.get();

    return 0;

    }


    6. Ref: “C Code Generation Using the MATLAB Coder App” from the matlab website.

    7. 备注

    (1) Overview选项卡中,点击Add files,弹出对话框,选中foo.m打开;

    (2) 单击变量a,选择Define by Example…,弹出MATLAB Coder Define by Example对话框,在MATLAB Expression中输入5,点击OK;同样变量b也进行相应操作,输入6

    (3) 选中Build选项卡,Output type中选择c/c++ Static Library;选中Generate code only

    (4) 点击More settingsGeneralàLanguage选择C++Interface选项中去掉所有选项;Close

    (5) 点击Build,进行编译;点击View report,弹出Code Generation Report对话框,此时,变量abc会显示相应的变量信息;

    (6) 利用vs2008建立一个控制台应用程序,将生成的相关文件foo.hfoo.cpprtwtypes.hfoo_types.h拷到相关目录下并添加到应用程序中;

    (7) foo.cpp文件中添加#include “stdafx.h”

    (8) test.cpp文件中代码为:

    #include "stdafx.h"

    #include "foo.h"

    #include <iostream>

    using namespace std;

    int _tmain(int argc, _TCHAR* argv[])

    { double a = 0.0, b = 0.0, c = 0.0;

    cin>>a>>b;

    c = foo(a, b);

    cout<<"c = "<<c<<endl;

    return 0;}

    7. 一个复杂的例子

    求一个数的n次方根:

    4.1两个.m文件:

    nrt.m:

    function [nth_rt, iterations, hstry] = nrt(varargin)%#codegen

    %This function will use a Newton Search Technique to find

    %the nth root of a number, a, to the tolerance, tol.

    %The square root

    % nrt(10, 2), or nrt(10, 2, 1e-9)

    %The "n" root

    %nrt(10, n), or nrt(10, n, 1e-9)

    a = varargin{1};

    n = varargin{2};

    if nargin ~= 3

    tol = 1e-9;

    else

    tol = varargin{3};

    end

    if a < 0

    nth_rt = 0;

    iterations = 0;

    hstry = 0;

    else

    [nth_rt, hstry] = newtonSearchAlgorithm(a, n, tol);

    iterations = length(find(hstry ~= 0));

    %iterations = sum(hstry ~= 0);

    end

    newtonSearchAlgorithm.m

    function [x, h] = newtonSearchAlgorithm(b, n, tol) %#codegen

    %Given, "a", this function finds the nth root of a

    %number by finding where: x^n-a = 0

    coder.inline('never'); %使其生成一个单独的c++文件

    notDone = 1;

    aNew = 0; %Refined Guess Initialization

    a = 1; %Initial Guess

    cnt = 0;

    h = zeros(50, 1);

    h(1) = a;

    while notDone

    cnt = cnt + 1;

    [curVal, slope] = f_and_df(a, b, n); % square

    yint = curVal - slope * a;

    aNew = -yint / slope; %The new guess

    h(cnt) = aNew;

    if (abs(aNew-a) < tol) %Break if it's converged

    notDone = 0;

    elseif cnt > 49 %after 50 iterations, stop

    notDone = 0;

    aNew = 0;

    else

    a = aNew;

    end

    end

    x = aNew;

    function [f, df] = f_and_df(a, b, n)

    %Our function is f=a^n-b and it's derivative is n*a^(n-1).

    f = a^n-b;

    df = n*a^(n-1);

    2 在命令窗口输入coder(图形界面),回车,弹出MATLAB Coder Project对话框;

    3、在New选项卡Name中输入一个工程名nrt.prj;点击Ok,弹出MATLAB Coder MEX Function对话框;

    4、在Overview选项卡中,点击Add files,弹出对话框,选中nrt.m打开;

    5、添加三个输入,分别为1021e-9;两个输入也可以;

    6、选中Build选项卡,Output type中选择c/c++ Static Library;选中Generate code only

    7、点击More settingsGeneral-->Language选择C++Interface选项中去掉所有选项;Close

    8、点击Build,进行编译;点击View report,弹出Code Generation Report对话框;

    9、利用vs2008建立一个控制台应用程序,将生成的相关文件nrt.cppnrt.hnewtonSearchAlgorithm.cppnewtonSearchAlgorithm.hnrt_types.hrtwtypes.h拷到相关目录下并添加到应用程序中;

    10、分别在nrt.cppnewtonSearchAlgorithm.cpp文件中添加#include “stdafx.h”

    11test.cpp文件中代码为:

    #include "stdafx.h"

    #include "nrt.h"

    #include <iostream>

    using namespace std;

    int _tmain(int argc, _TCHAR* argv[])

    {

    double varargin_1 = 0, varargin_2 = 0, varargin_3 = 1e-9;

    cin>>varargin_1>>varargin_2;

    double nth_rt = 0, iterations = 0;

    double hstry_data[50] = {0};

    int hstry_sizes[1] = {0};

    nrt(varargin_1, varargin_2, varargin_3, &nth_rt, &iterations, hstry_data, hstry_sizes);

    cout<<"nth_rt = "<<nth_rt<<endl;

    cout<<"iterations = "<<iterations<<endl;

    cout<<"hstry_data = "<<endl;

    for (int i=0; i<50; i++)

    {

    cout<<hstry_data[i]<<endl;

    }

    cout<<"hstry_sizes = "<<hstry_sizes[0]<<endl;

    return 0;

    }

    感谢 [南极粥](https://me.csdn.net/zyqdragon)
    展开全文
  • Android底层调用C代码(JNI实现)

    万次阅读 2017-08-05 12:51:09
    Android底层调用C代码(JNI实现) 一、基础知识 二、从Android框架角度简单分析JNI 三、标准JNI实现步骤 四、实现JNI过程实例 一、基础知识 1、JNI:百度百科中解释:JNI是Java Native Interface的缩写,它...


    Android底层调用C代码(JNI实现)

    • 一、基础知识
    • 二、从Android框架角度简单分析JNI
    • 三、标准JNI实现步骤
    • 四、实现JNI过程实例

    一、基础知识

    1、JNI:百度百科中解释:JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++)。
    (然而就像官话一样难理解)。
    个人理解,JNI就是一个可以通过Java虚拟机(JVM)执行C/C++代码的接口,有了JNI,就可以在Android应用中与其他语言写的程序代码进行交互。。可以说是Android最重要的一个功能接口,

    2、NDK:Native Development Kit 的缩写,如英文意思,是Android提供的一套工具,重点是包含实现JNI功能的一些命令


    二、从Android框架角度简单分析JNI

    这里写图片描述

    (专业盗图)
    其中Application层和Firmware层都是Java代码编写,而底层众多Libararies、Kernel和一系列驱动程序都是C/C++代码写的,
    因此上层Java要调用底层的C/C++函数库必须通过JNI来实现,可以说JNI是底层到App层的一个桥梁。

    有兴趣了解各层次可以看下面分层描述:(从我以前大论文摘的,终于用上一次了!)
    (1)操作系统内核层(Kernel)
    Android系统基于Linux内核作为整个系统的基础核心,依托Linux内核强大的内存管理、进程控制、网络管理以及安全管理等能力,使得Android系统的整体性能得到提升;Google公司针对移动设备的特点,基于Linux驱动模型添加了移动设备中常用的驱动程序,例如音频驱动、摄像头驱动等,极大提升了系统的可扩展性。Linux内核之上,Linux内核也同时作为软件层之下的硬件抽象层(Hardware Abstract Layer),负责对Linux内核驱动程序的封装,并向上提供接口。

    (2)核心库(Libraries)与运行环境层(Android Runtime)
    该层的核心函数库都与移动设备平台的应用密切相关,其中大部分都是基于C/C++语言,通过使用Java提供的JNI(Java Native Interface)接口Android上层应用使用,方便应用程序开发与维护。Android基于Dalvik虚拟机技术实现系统运行环境,具有较好的硬件优化能力,更加适合移动设备领域应用。

    (3)应用框架层(Application Framework)
    应用框架是Android应用开发的基础,为开发人员提供各种API接口;该层首先实现了Android应用程序中的各种组件,并且在遵循框架安全限制的前提下,任何应用程序之间都可以相互发布其功能并使用,使得应用程序开发更加便捷。

    (4)应用层(Application)
    Android应用层包括在系统上运行的应用程序,还包括安装在设备上的第三方应用,第三方应用的开发都是基于Android提供的SDK工具包(Software Development Kit),并且都是使用Java语言编程;开发人员可以利用Android应用框架层进行应用程序的开发,也可以绕过框架层直接使用NDK(Native Development Kit)进行开发。


    三、标准JNI实现步骤

    准备工作:首先要下载NDK,然后配置环境变量,如果用Android Studio ,需要添加NDK目录到Local.properties,并且在App目录中添加so名字到Build.gradle

    步骤如图:
    这里写图片描述

    一般步骤都是要先编写Java 类代码,里面定义Native方法名;
    编译后,通过NDK中的Javah命令生成接口文件xxx.h,之后就可以用C/C++语言实现各类方法,并且编译生成的libxxx.so文件,供上层调用。


    四、实现JNI过程实例

    第一步:创建Java类,其中的方法需要用native关键字修饰,例如。

    这里写图片描述

    其中,Java代码加载JNI的库是调用System.loadlibrary方法加载,这里的mms库就是编译的 一个C动态链接库,是 通过NDK-build进行比哪一 然后包含进行app代码中如下:

    这里写图片描述

    第二步:使用javah命令(javah 类的全路径)生成本地方法的C++头文件.h

    这里写图片描述

    这一步会自动生成Native方法对应的接口函数,如 生成com_xxxx_finaltest_NativeMocana.h里面就是test的接口函数

    这里写图片描述

    第三步:编写C/C++本地代码,Rebuild 生成动态链接库文件 libmms.so

    这里写图片描述

    第四步 :Java调用本地函数,实现对底层C代码的调用。

    这里写图片描述


    附更改Android Studio JDK、SDK、NDK路径方法:

    这里写图片描述

    ##欢迎转载,Howie原创作品,本文地址:

    http://blog.csdn.net/HowieXue/article/details/76714314

    ##谢谢

    展开全文
  • Notepad++ 运行 C 代码

    万次阅读 2018-09-21 09:37:13
    在Windows环境下编译C代码,自然离不开MinGW,而MinGW也有还几个选择,比如,仅支持32bit的MinGW,支持32bit和64bit的MinGW-m64,还有TDM-gcc(据说也是基于MinGW-m64的非官方维护版本)。见贤思齐,自然要选择MinGW...
  • 本文描述通过通过Stateflow调用外部C代码调用外部C代码的方法。 文章目录1 问题引入2 调用外部C代码的过程2.1 准备外部文件2.2 搭建模型2.3 生成代码3 调用有参数和返回的函数4 总结 1 问题引入 情形1:在汽车嵌入式...
  • MATLAB Coder可以从MATLAB代码生成...1. 使用MATLAB Coder产生C代码的4个步骤: (1) 开发实现特定算法功能的MATLAB代码及其测试文件; (2) 检查MATLAB代码的兼容性,确保MATLAB代码中的语句都能被转换成C代码(有些m
  • 基于MATLAB Coder将matlab代码转换成C代码 官网视频讲解 matlab调用c/c++代码 特此感谢! 一、概念及开发流程 MATLAB Coder可以从MATLAB代码生成独立的、可读性强、可移植的C/C++代码。 通俗地说,就是将写好的ma.....
  • android studio 使用jni写C代码,可以设置代码提示吗?
  • 51单片机流水灯电路以及C代码

    万次阅读 多人点赞 2018-10-25 10:00:20
    流水灯是51单片机的入门级实验,以下是其电路图以及C代码 流水灯proteus电路图 此图发光二极管采用共阳极式连接 流水灯C代码 #include&amp;amp;amp;amp;amp;amp;amp;amp;lt;reg51.h&amp;amp;amp;amp;...
  • Simulink转C代码的实现

    千次阅读 2019-09-03 23:03:26
    本报告为Matlab仿真框图转C代码实现说明文档。 实现步骤 1.搭建框图 采用Matlab 2016b搭建仿真框图如下,命名为test.dll。 图 1Simulink模型 2.初始设置 选择菜单栏Simulink->ModelConfiguration ...
  • Matlab 2019b simulink 生成C代码(一)

    千次阅读 2020-03-08 14:40:43
    本文主要以matlab 2019b版本,主要讲解怎么用simulink生成嵌入式c代码: 1.设置生成嵌入式C代码; 2.生成自己想要变量代码; 二、具体实现方法 1.我们以FOC控制坐标变换Clark变换为例: Ialpha = Ia; Ibeta =...
  • C代码变成可执行文件的过程

    万次阅读 2018-08-01 21:26:26
    C代码是如何变成程序的 C语言是一门典型的编译语言,源代码文件需要编译成目标代码文件才能运行。可以认为程序文件就是编译好的目标代码文件。以GCC的编译过程为例。GCC的翻译过程可以分成四个阶段:预处理器、...
  • C 代码转化为C++代码

    千次阅读 2007-06-09 18:04:00
    下载本文例子的源代码C代码转化为C++代码,不进行风格转化,不做重构,仅仅为了代码能够通过C++编译器。1.全局函数和全局变量声明和调用。改为C++代码后,C++编译器对函数的修饰名(name mangle)和C编译器不一样,...
  • ruby中如何直接编译运行C代码

    千次阅读 2014-11-30 20:46:05
    我们知道ruby通过C EXT可以很方便的运行C代码,其实只要是C接口的语言都可以,比如汇编语言也可以哦。但是一些简单的函数难道害得费劲用C扩展的方式吗?其实ruby gem里有RubyInline包,通过它可以在ruby源代码里写C...
  • c代码,不是c++。 希望是比较完整的代码,而不是一个子程序。 感谢!
  • c代码覆盖率工具

    千次阅读 2014-05-12 11:11:15
    C/C++程序的代码覆盖率统计工具非常少,与JAVA相比开源免费的工具更是寥寥无几,好用又...二是NGINX是纯C的程序,GCOV对纯C代码的覆盖率展现更加精确;三是LCOV作为GCOV的扩展,能够生成直观的HTML的带源码的覆盖率报
  • Java代码转C代码经验

    千次阅读 2007-12-20 18:12:00
    在基本理解的情况下,我打算将其代码转化为C代码,以提高其速度。里面一些要进行字符处理,感觉JAVA太上层,有点不好掌控。C语言自由度大,易于操作和处理。我首先针对JAVA中的BEAN包进行了C语言改写,在进行改写的...
  • 关于androidstudio工程C代码跳转问题

    千次阅读 2017-03-07 10:06:39
    我现在的工程中有用到NDK开发,那么有时候公司会有一些C代码的修改问题 我就为了方便把C代码copy到了工程目录中,那么唯一的一个问题就是想要androidstudio里面C代码能正常的跳转 像java代码一样 ctrl+单机能跳转  ...
  • 使用LCOV统计代码覆盖率(c代码

    千次阅读 2011-03-08 18:06:00
    使用LCOV工具,统计代码覆盖率,针对c代码
  • Swift调用C代码的方法

    千次阅读 2015-08-09 19:25:30
    本篇纪录的是Swift中调用C代码的方法,我使用的是MAC OS X10.10.4的系统,Xcode7beta版,下面是swift调用C的步骤: 1.新建一个命令行工程,取名为TestSwift01 2.创建Objective-C文件,在项目上鼠标右键,选择New ...
  • 均值滤波代码 C代码

    千次阅读 2017-07-15 21:04:02
    // 本函数是实现 3 * 3 均值滤波 //函数的的当前点的像素 = 3 * 3 范围的平均值 // @para src 输入图像数据 // @para srcW 输入图形宽 // @para srcH 输入图像的高 // @para channels 通道数 // @para dest 输出...
  • GO中调用C代码(CGO)中的坑

    万次阅读 2016-08-16 21:33:00
    GO中调用C代码(CGO)中的坑GO中调用C代码CGO中的坑 背景 问题重现 问题解决背景网上有很多讲解使用CGO实现GO中调用C代码的博客。总结起来,Go中调用C一共有两种办法: 第一种是将C代码直接嵌入到GO源文件中 第二种...
  • Matlab生成C代码

    万次阅读 2017-10-25 22:17:15
    matlab功能强大,其中很重要的一点是生成c/c++代码,该代码可以直接移植到项目中,免去了我们自己的复杂计算,下面介绍matlab如何生成c/c++代码。 matlab使用版本:2014a 1.新建m文件 新建m文件的方式有两种。a...
  • 使用可靠的I2C代码

    千次阅读 2014-05-05 23:53:25
    现有的STM32的I2C代码,由于没有使用STM32官方推荐的DMA+I2C中断优先级最高的方式,总感觉用着不放心。想要修改,却又不知道如何改是更好地。于是想查找I2C驱动部分处理的好的代码,参照将现有I2C部分程序重构下。在...
  • vscode编译运行C代码

    千次阅读 2019-08-31 16:42:37
    文章目录代码准备工作launch.jsontask.json 代码准备工作 1、新建目录     vscode是不能直接新建工程的,需要先新建目录,存放代码 ...3、新建 .c、.h 代码文件     以新建main.c文件为...
  • JNI实现Java调用C代码Demo AndroidStudio

    千次阅读 2015-09-19 01:57:40
    JNI(Java Native Interface)的本意是Java本地调用,它是为了方便java调用C/C++等本地代码所封装的一层接口 Android NDK(Native Development Kit )是...提高代码安全性,本地C代码反编译困难 - 2.方便的使用成熟C开
  • 最小二乘法曲线拟合+C代码

    千次阅读 2015-07-30 21:54:54
    最小二乘法曲线的系数求解过程是解一个正规方程组的解的过程,下图是数值分析课本...c代码如下: #include "stdio.h" #include "stdlib.h" #include "math.h" #include "vector" using namespace std; struct
  • “多线程”简介及其C代码实现框架

    万次阅读 2015-11-16 18:42:48
    本文对“多线程”进行了简单的介绍,并给出了其C代码的实现框架。“单线程”程序 要想理解“多线程”,那么就要先从“单线程”说起。 大家都知道工厂“流水线”作业,里面的工序是一环扣一环的

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 430,275
精华内容 172,110
关键字:

c代码