精华内容
下载资源
问答
  • 嵌入式内核为什么选择C语言C语言的特点:具有出色的可移植性,能在多种不同体系结构的软/硬件平台上运行;(1)可移植性是指在移植到别的操作系统的时候,需要修改的代码越少,移植性越好。举个例子,假如我们要...

    C语言之父:丹尼斯里奇

     

    C语言的标准:K&RC    ANSI C/C89  C99  C11

     

    嵌入式内核为什么选择C语言?

    C语言的特点:具有出色的可移植性,能在多种不同体系结构的软/硬件平台上运行;(1)可移植性是指在移植到别的操作系统的时候,需要修改的代码越少,移植性越好。举个例子,假如我们要做一个实现空调功能的程序,我们肯定会先找一个空调芯片看一下源代码是怎么实现功能,然后根据自己的需求修改源代码。如果该程序是用java编写的,那还要求程序员能够看懂java,然后再用C编写,这样效率就会很低下。而如果使用C编写的就会为我们带很大便利。(2)在嵌入式学习中我们都知道最重要的就是操作系统,也就是上文所说的体系结构。我们以图书馆借书系统为例。我们相当于用户,图书管理员相当于操作系统,图书相当于硬件。当没有管理员的时候我们需要清楚图书馆的构造以及一本书放在什么位置才可以借到书,而有了管理员之后,我们只需要将需要借的书告诉管理员让管理员去找书就可以了。有了操作系统用户访问硬件的速率也快了很多。

                  具有简洁紧凑、使用灵活的语法机制,并能直接访问硬件。内核使用来管理软件和硬件资源的。访问硬件我们可以分为直接访问间接访问硬件。这里就涉及到一个效率的问题。直接访问的效率高,而能够直接访问硬件的语言只有c语言和汇编语言,因为汇编是低级语言,没有高级语法所以我们只有在对简单硬件的初始化才使用汇编语言。这也是我们嵌入式学习为什么选择C语言的原因。

                  具有很高的运行效率。以图书馆借书为例我们也可以看出效率提高了很多。

    展开全文
  • 世界上绝大部分的操作系统内核都是用C语言编写的,然而这是为什么喃? 这个问题我们就必须结合C语言的特点了! C语言有三大特点: 1 非常好的可移植性 可移植性就是指与软件从某一环境转移到另一环境下的...

    世界上绝大部分的操作系统内核都是用C语言编写的,然而这是为什么喃?

    这个问题我们就必须结合C语言的特点了!


    C语言有三大特点:


    1 非常好的可移植性

    可移植性就是指与软件从某一环境转移到另一环境下的难易程度。也就是更换不同体系结构的软/硬件平台,修改的代码越少越好。因为不同机器的C语言源码(主要是函数库中的函数名和其参数)都是差不多的,所以C语言的可移植性好。


    2 能够直接访问硬件

    操作系统需要和下层的硬件打交道,直接访问硬件就可以提高效率,这对于操作系统来说很重要。能直接访问硬件的语言还有汇编语言,但为什么操作系统不用汇编语言?因为汇编是低级语言,不能实现操作系统复杂的功能。C语言是高级语言也容易阅读和理解。


    3运行效率高

    操作系统需要对上层的需求做出快速的反应,所以这点也很重要。


    综合以上几点,C语言是首选。


    一个在努力中的未来程序员,如果有更好的想法,欢迎评论。

    展开全文
  • Linux内核的创始人Linus Torvalds最 近在一封邮件中说明了内核开发需要使用C语言而非C++的理由

    Linux内核的创始人Linus Torvalds最 近在一封邮件中说明了内核开发需要使用C语言而非C++的理由。 Name: Linus Torvalds (torvalds@linux-foundation.org) 6/8/10 anon2 (anon@anons.com) on 6/8/10 写道: > >效率对于内核的开发是个至关重要的问题。 >大部分志愿者为内核贡献代码,所以在相 >同条件下,使用更高效的语言能让你的工 >作效率提升,从而更快更出色的完成开发。 事实上,你错了 志愿者贡献的代码很优秀,而且他们似乎没有觉得语言的效率是个障碍。如果改换语言真的能提高效率,那么这将是使大众受益的事情——不仅仅是经济方面 的。一行行的写代码,而不和用户交流,即使使用再有效率的语言都是无用的,很多大型项目都有这个问题的。 内核方面,我们有大约1000个志愿者者为每一个内核的释出做着贡献(3个月前统计的结果)。现在有更多的人加入,但是我更为担心的不是代码,而是 编码方面的持续性和linux内核的发展方向。现在,我已不写代码很多年。我目前主管志愿者的代码是否进入内核,如果代码可以进入内核,我就说ok,进去 吧;如果不能,我就说No——当然这种情况比较少。 如果想做好一个产品,最重要的就是要与客户进行交流。内核的编写也是如此,缺乏交流是整个项目的瓶颈……避免交流缺失最好的办法就是拥有共同的 “culture”(信仰吧……),或者拥有共同的默契感(原文:潜规则,汗之~)。我们有很多文档指导人们如何去做以及怎样去做,但是在不同文化背景的 人们面前,这些文档是那么苍白无力…… (有很多书在介绍文化,你甚至可以在大学取得一个相关的PhD学位,然后穷极一生去学习,但是,但是你却从来没有深入了解过自己……) c语言呢,也有自己的“文化”(Unix也是如此——让我想起了KISS)。一个语言,就应该简单而明确,而不是复杂冗余。c++有一个绝对让我不 爽的“特性”—— context-dependent,这只是意味着, 当你阅读代码时,本地视图(local view)却不能给你任何帮助。 这,在交流上可是个大问题……在庞大的项目中,人们对不是自己开发的模块并不了解,能快速理解其他模块中函数的确切含义才能提高开发效率,而C++ 引入的各种抽象则使代码变得晦涩难读。 如果你想提交代码(或者补丁),是不是感觉 “sctp_connect()” 比 “connect()” 简洁而且明了呢?(匈牙利命名?) ,剩下的交给编译器吧,编译器能知道你写的是sctp协议模块的,并完成一切。 项目开发中,我们尽量使用补丁和分支,邮件列表等形式,而不是对源码进行整体修改,这是因为唯一重要的在于改变,而不是结果。所以,这也是我们避免 歧义和代码关联性(context)的根本原因。——尤其是在内核项目上,绝对不能有半点马虎。绝大多数软件工程上都是如此,其实在日常交往中也应该如 此:说话含糊不正常的得不到好处。 因此,一个语言应该简单而明确。你不必顾虑过多,也不用学习冗长的语法和你不需要的东西。如果每个人都是项目专家,那么隐含方式调用函数 (implicit context)是个不错的主意——这就是为什么真正深奥的科学文献,基本上都是晦涩难懂的,除非你是一个专家,拥有大量的背景知识以及要素,才能有所了 解。但是如果是一个多人参与的大型项目,呃,这几乎是不可能的。 例如,我非常了解 VM 部分的代码,但我仍然需要读取各文件系统和网络的代码。即使像我这样了解的人,仍然把代码写的简明扼要,绝不会有任何“隐藏代码”。c就是这样一个语言, 读代码,就能知道它的作用。一个函数用来做一件事,而这个函数也只作这一件事情,不会再出现一些“微妙的问题”——这是“哪个版本的一个函数调用”。 这也就是为什么我认为c语言“简约而不简单”——尤其是对于一个os的内核来说,尤为重要;在特定的编程或系统亦是如此。这也是为什么我不认为在所 有项目中c都适合的原因。 不过,c++……我真得不认为它有什么出色的地方。垃圾回收和并发等等,这些才是真正重要的特性。可是c++……完全落在了c后边…… linus (业余翻译,不当之处恳请指出,谢谢!) 原文: http://www.realworldtech.com/forums/index.cfm?action=detail&id=110618&threadid=110549&roomid=2

    展开全文
  • Linux内核GNU C编写,从而必须gcc编译,另外gcc编译器在发展过程中,在不断的扩展和舍弃一些东西,所以就会出现一种情况:高版本gcc编译不了低版本内核、低版本gcc也编译不了高版本内核。所以在编译内核时,...

    本文转自网络文章,内容均为非盈利,版权归原作者所有。
    转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。
    原文作者:jmpcall
    专栏地址:https://zhuanlan.kanxue.com/user-815036.htm

     1. Linux内核中的C语言

        Linux内核是用GNU C编写,从而必须用gcc编译,另外gcc编译器在发展过程中,在不断的扩展和舍弃一些东西,所以就会出现一种情况:高版本gcc编译不了低版本内核、低版本gcc也编译不了高版本内核。所以在编译内核时,一定要使用跟内核版本差不多时期的gcc版本。

     

    • 带返回值的宏函数
    #include <stdio.h>
    #define FUN() ({ \
        int ret = 100; \
        printf("do something ..\n"); \
        ret; \
    })
     
    int main()
    {
        int m = FUN();
     
        printf("%d\n", m);
        return 0;
    }

    执行结果:

    do something ..
    100

     

    • do {} while (0)

            宏函数DUMP_WRITE(),在如下情况被调用时:

    if (addr)
        DUMP_WRITE(addr,nr);
    else
        do_something_else();

    按照如下两种方式定义,在被调用处展开后,都有问题:

    #define DUMP_WRITE(addr,nr) memcpy(bufp,addr,nr); bufp += nr;
    #define DUMP_WRITE(addr,nr) { memcpy(bufp,addr,nr); bufp += nr; }

    而利用"do {} while (0)"将多条语句包在一起,无论怎么调用,都不会有问题:

    #define DUMP_WRITE(addr, nr) do { \
        memcpy(bufp, addr, nr); \
        bufp += nr; \
    } while (0)
    • [first ... last] = value

            这是GUN C相对于ANSI C的一个扩展,用于将数组某个区间,初始化为非0值,比如:

    int array[100] = { [0 ... 9] = 1, [10 ... 98] = 2, 3 };
    • include/linux/list.h

            GUN C相对于ANSI C的扩展还有很多,书上已经列举了一小部分,更具体的,可以到后期学习代码时遇到了,再逐个了解。相对的,我认为include/linux/list.h这个头文件里面的代码,必须要在一开始就看懂,因为这里面的接口,大量用于内核的代码中,同时我觉得这种设计的思维也很精妙。

     

            它用于构造双向循环链表, 从如下两份代码的对比中,应该就可以感受到它的好处:

          

      代码1:

    #include <stdio.h>
     
    struct data_node {
        int               n;
        char              c;
        struct data_node *prev;
        struct data_node *next;
    };
     
    int main()
    {
        struct data_node datas[4] = {
            { 1, 'a', NULL, NULL },
            { 2, 'b', NULL, NULL },
            { 3, 'c', NULL, NULL }
        };
        struct data_node *head = &datas[0];
     
        // 添加节点、遍历链表,需要业务层本身实现
        datas[0].prev = &datas[2];
        datas[0].next = &datas[1];
     
        datas[1].prev = &datas[0];
        datas[1].next = &datas[2];
     
        datas[2].prev = &datas[1];
        datas[2].next = &datas[0];
     
        while (1) {
            printf("datas[%d]: n=%d, c=%c, prev=%p, next=%p\n",
                head->n - 1, head->n, head->c, head->prev, head->next);
            if (head->n == 3)
                break;
            head = head->next;
        };
     
        return 0;
    }

    运行结果:

    datas[0]: n=1, c=a, prev=0xbfc5c84c, next=0xbfc5c83c
    datas[1]: n=2, c=b, prev=0xbfc5c82c, next=0xbfc5c84c
    datas[2]: n=3, c=c, prev=0xbfc5c83c, next=0xbfc5c82c

    代码2:

    #include <stdio.h>
    #include "list.h"
     
    struct data_node {
        int              n;
        char             c;
        struct list_head list;
    };
     
    int main()
    {
        struct data_node datas[4] = {
            { 1, 'a', { NULL, NULL } },
            { 2, 'b', { NULL, NULL } },
            { 3, 'c', { NULL, NULL } }
        };
        struct list_head head = LIST_HEAD_INIT(head);
        struct list_head *pos;
     
        // 添加节点、遍历链表,业务层直接调用接口
        list_add_tail(&datas[0].list, &head);
        list_add_tail(&datas[1].list, &head);
        list_add_tail(&datas[2].list, &head);
     
        printf("head: %p, prev=%p, next=%p\n", &head, head.prev, head.next);
     
        list_for_each(pos, &head) {
            struct data_node *data = list_entry(pos, struct data_node, list);
            printf("datas[%d]: n=%d, c=%c, prev=%p, next=%p\n",
                data->n - 1, data->n, data->c, data->list.prev, data->list.next);
        }
     
        return 0;
    }
    

    运行结果:

    head: 0xbf9ad48c, prev=0xbf9ad474, next=0xbf9ad454
    datas[0]: n=1, c=a, prev=0xbf9ad48c, next=0xbf9ad464
    datas[1]: n=2, c=b, prev=0xbf9ad454, next=0xbf9ad474
    datas[2]: n=3, c=c, prev=0xbf9ad464, next=0xbf9ad48c

     

    • list_entry()

            include/linux/list.h这份代码整体不难,但是如果是刚开始学习,可能会对宏函数list_entry()有些疑惑:

    #define list_entry(ptr, type, member) \
        ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

    ① 首先要明白的是:为什么需要这个宏函数?

    代码1中,datas[1].prev,直接就是&datas[0],而代码2中,datas[1].list->prev,只是&datas[0].list而已,想知道&datas[0]的话,还需要减去list成员相对于结构体开始的偏移,知道目的后,再去理解这个宏函数就不难了。

     

    但是,还有值得注意的地方:"&((type *)0)->member",按照平时开发程序的经验,可能觉得这里会coredump!

    直接举例:

    #include <stdio.h>
     
    struct test {
        int  n;
        char c;
    };
     
    int main()
    {
        struct test *p = NULL;
     
        //printf("%d, %c\n", p->n, p->c);    // coredump
        printf("%p, %p\n", &p->n, &p->c);    // 不coredump
        printf("%p, %p\n", &((struct test*)0)->n, &((struct test*)0)->c);    // 不coredump
     
        return 0;
    }

    这样,就可以推测出来一个过程,我们平常在C程序中写的"p->n",其实等价于"*(&p->n)","&p->n"前面有个显式的&,则只是根据p的地址,计算成员n的地址,哪怕"p=NULL"也没关系,coredump只是发生在访问这个错误地址的时候而已。

     

    2. Linux内核中的汇编代码

    • Linux内核使用汇编的场合

            ① 有些操作硬件的专用指令,在C语言没有对应的语言成分,比如给GDTR/LDTR寄存器赋值的特权指令:LGDT/LLDT

            ② 某些场合,对效率要求极高,或者对执行时间有精准的要求

            ③ 某些场合,对程序的体积也有极端的要求,如引导程序

     

    • Linux内核使用汇编的形式

            ① 纯汇编代码。比如学习到第10章"系统的引导和初始化"时,就会遇到纯汇编文件bootsect.S、sctup.S,另外,后缀如果是大S,里面可能会包含一些C语言中的预处理语句,后缀为小s,就没有任何其它语言的影子;

            ② 嵌入式汇编。在C函数中,可以按照__asm__ __volatile__ (“指令部:输出部:输入部:损坏部”)格式,嵌入一块汇编语言(稍后举例)。

     

    • AT&T格式与intel格式比较

            从网上可以查到很详细的资料,我觉得刚开始学,只需要对一些符号(比如:$、%)有印象即可,在看代码时遇到了,再去确认具体的含义。

    • 嵌入式汇编/内联汇编

            书1.5.2节,最后举了内核中2个使用了内联汇编的函数:__memcpy()、strncmp()。

            (这个图我在chinaunix发过,所以不是抄袭)

            汇编代码块前后,是可以有C语句的。

        ① 所有用双引号包围的内容,为"指令部",从紧接着指令部的冒号开始,依次标记为0、1、2、..

            指令部后面第一个冒号开始,为“输出部”,用于指定C的各个变量,由哪些寄存代替。例子中,用ecx作d0,用edi作d1,用esi作d2;
            指令部后面第二个冒号开始,为“输入部”,用于初始化变量。例子中,"0"标号对应的"ecx/d0"=n/4,"q"让编译器从eax/ebx/ecx/edx选择一个进行使用,并且初始化为n,"1"标号对应的"edi/d1"=to,"2"标号对应的"esi/d2"=from;
            指令部后面第三个冒号开始,为“损坏部”,指令部和输出部中的寄存器,在执行过程中,都有可能被修改掉,如果希望某些寄存器的值保持不变,就可以在损坏部指定,编译器就会在入口添加压栈保存、在出口添加出栈恢复的指令。


        ② "指令部"分析:
            "输入部"已经完成了初始化:ecx = n/4,eax = n,eid = to,esi = from;
            第一条指令"rep; movsl\n\t":重复执行movsl n/4(ecx)次,每次从from(esi)拷由4byte到to(edi),执行完可能还剩1~3字节没有拷贝;
            第二条指令"testb $2,%b4\n\t":AT&T格式中,"$数字"表示立即数,"%数字"表示输入/输出部相应标号处的内容,所以这条指令就是判断%4(拷贝长度n)的低第二位是否为1(代码中为"%b4",不确实是不是告诉编译器尽量用ebx的意思),如果为1,则至少还剩2字节,所以执行第四条指令"movsw",再拷贝2字节,否则执行第三条指令"je 1f\n\t"("f"表示forward,往前方最近的1标号处跳转),直接跳转到"1:\ttestb $1,%b4\n\t";

            第五条指令,同样的道理,判断是否还剩1字节没的拷贝,如果是,则会执行"movsb"指令,再拷贝1字节。

     

        ③ 执行效率

            由于这个函数的使用频率极高,所以内核直接使用汇编实现,让函数简洁到了极限,没有任何一条多余的指令。感兴趣的话,可以用C语言写一个__memcpy(),用不同的优化级别编译,然后反编译和内核中的这个函数对比,感受一下。

    展开全文
  • Linux内核工程导论——内核为何使用C语言

    千次阅读 多人点赞 2015-10-12 20:53:15
    C与C++的对比无数人说过...一般大部分人的心态是,学C++出身的,就经常吐槽linux的C代码乱的一塌糊涂,各种敏捷,面向对象原则,代码不如C++精简,连个STL或者boost都不上,等软件工程相关问题都是被他们吐槽的重灾区
  • Linux内核中常用的C语言技巧

    千次阅读 2019-03-06 09:03:20
    Linux内核中常用的C语言技巧 相信读者在阅读本文之前已经学习过C语言了,但是想...GCC的C编译器除了支持ANSI C标准之外,还对C语言进行了很多的扩充。这些扩充对代码优化、目标代码布局以及安全检查等方面提供了很...
  • c语言内核链表

    2018-08-16 19:25:34
    c语言内核链表主函数,适用于Linux平台的。可以直接套用,
  • C语言内核等待队列机制介绍C语言内核等待队列机制介绍C语言内核等待队列机制介绍
  • Linux内核中不能使用C语言的标准库。 我们讲道理: 操作系统内核提供一个应用程序接 口(API)给应用程序调用,有一些功能比较常用,于是把这些功能做成了一个函数库,叫C语言的标准库。于是C语言的标准库是依靠操作...
  • 投资自己,什么时候都不晚。 和Unix一样,Linux内核也是用C语言实现的。谈到C,几乎所有的人都会立即想到ANSIC标准。...内核开发者使用C语言涵盖了ISO C99标准和GNU C的扩展特性,我想,其中让人感兴趣的,应该...
  • 我们的操作系统通过增添内核接口导出机制后,已经可以作为平台,运行应用程序了,但目前应用程序的开发有一个不足就是,我们只能使用汇编语言开发应用程序,汇编语言开发程序实在太累了,如果能使用C语言就好了,...
  • 在阅读linux2.6 版本内核的虚拟文件系统和驱动子系统的时候,我发现内核用c语言编写其实也是有一点不方便,特别是内核中大量存在了对象的概念,比如说文件对象,描述起来使用对象描述,但是对象在c语言中的构建远...
  • 深入php内核,从底层c语言剖析php实现原理 非常好的电子书:http://www.cunmou.com/phpbook/preface.md   这是它的目录: PHP的生命周期 让我们从SAPI开始 PHP的启动与终止 PHP的生命周期 线程安全 ...
  • linux 内核使用c语言写的

    千次阅读 2012-11-14 18:01:40
    C++效率要高于C,可以比较一下std::sort和qsort的效率。...Linux用C和汇编,而不是C++还因为 1、在Linux写出来得时候,C++还是一门比较新的语言,尚在标准化之中(C++在1998年才标准化完,而Linux在1991年就出了0.
  • linux内核源代码的C语言代码

    千次阅读 2014-06-10 21:38:44
    C语言支持一些属性描述符,而gcc同样支持不少这样的描述符,这些描述符的使用等于在C语言中增加了一些新的保留字,此时,原来的C语言中这些词可能并不是保留字,一旦老的代码中刚好有变量名与此描述符一样,就会冲突...
  • linus说了,内核用c。(语言与实现逻辑没有必然关系,C++不够透明,干了很多程序员不知道的事。内核要稳定,可靠,高效。c对应汇报短小精干。) Other 内核时计算机为数不多知道电脑要干什么的情形 Reference ...
  • C语言下的内核链表

    2019-04-01 13:44:02
    使用内核链表的时候,将内核链表作为一个成员放入到一个结构体中使用 我们在链表中找到内核链表结构的地址,通过这个地址就可以找到外部大结构体的地址,通过大结构体就可以访问其中的成员 优势: 内核链表突破了...
  • 内核红黑树MAP--C语言

    2019-01-17 11:08:15
    封装了linux 内核 红黑树,纯C语言,外层已经封装好了,直接使用,有压力测试,很不错
  • Linux 内核和 Windows 内核什么区别?

    千次阅读 多人点赞 2021-02-20 09:46:29
    对于服务器使用的操作系统基本上都是 Linux,而且内核源码也是开源的,任何人都可以下载,并增加自己的改动或功能,Linux 最大的魅力在于,全世界有非常多的技术大佬它贡献代码。 这两个操作系统各有千秋,不分...
  • Linux 内核Linux 内核Linux 内核Linux 内核Linux 内核Linux 内核
  • 以下阅读内核代码是觉得以前自己没有过的C语言使用方式 ----------------------------------------------------------- 1. 数组的初始化  内核代码:kernel/cpu.c 中 cpu_bit_bitmap 初

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 660,836
精华内容 264,334
关键字:

内核为什么用c