Android NDK 1 C语言基础

一、C语言的起源

C 语言是贝尔实验室的 Dennis Ritchie 于 1969 年 ~ 1973 年间创建的。美国国家标准学会(ANSI)在 1989 年颁布了 ANSI C 标准,后来 C 语言的标准化成了国际标准化组织(ISO)的责任。这些标准定义了 C 语言和一系列函数库,即 C 标准库。

  • C 语言与 Unix 的关系

C 语言从一开始就是作为一种用于 Unix 系统的程序语言开发出来的。大部分 Unix 内核,以及所有支撑工具和函数库都是用 C 语言编写的。

  • C 语言小而简单

C 语言的设计是由一个人而非一个协会掌控的,它是一个简洁明了、没有什么冗赘的设计。C 语言经典著作 《The C Programming Language》(K & R)中包含大量例子和练习描述了完整的 C 语言及其标准库,而全书还不到 300 页。

  • C 语言是为实践目的设计的

二、C 语言概述

C 语言目前最新版本由 ISO/IEC 9899:2011 定义。当前版本一般称为 C11,但是 C11 中一些语言元素是可选的,这就意味着遵循 C11 的编辑并没有实现该变准中的所有功能。

C11 标准是 ISO/IEC 9899:2011 - Information technology -- Programming languages -- C 的简称,曾用名为 C1X。

C11 标准是 C 语言标准的第三版,前一个标准版本是 C99 标准。2011年12月8日,国际标准化组织(ISO)和国际电工委员会(IEC) 旗下的C语言标准委员会(ISO/IECJTC1/SC22/WG14)正式发布了 C11 标准。

2.1 标准库

C 标准库也在 C11 标准中指定,标准库定义了编写 C 程序时常用的常量、符号和函数,还提供了一些 C 语言的一些可选扩展。标准库在一系列标准文件:头文件(.h)中指定。

三、创建 C 程序

C 程序的创建由以下四个步骤:

  1. 编辑

  2. 编译

  3. 链接

  4. 执行

下面就来详细分析每个步骤:

3.1、编辑

编辑过程就是创建和修改 C 程序的源代码。

3.2、编译

编译器将源代码转换为机器语言,在编译过程中会找出并报告错误。该阶段的输入是在编辑期产生文件(源文件)。编译器的输出结果称为对象代码(object code),存放它们的文件称为对象文件(object file),在 Linux/Unix 通常是.o。

下面是一个在 Linux 下编译的示例:

hello.c 源文件:

#include <stdio.h>

int main()
{
    printf("hello,world\n");
    return 0;
}

编译指令:

cc -c hello.c  或 gcc -c hello.c

gcc 指令的一般格式为:gcc [选项] 要编译的文件 [选项] [目标文件]

以上指令中 hello.c 是需要编译的源文件,生成的文件为 hello.o;如果省略了 -c 这个参数,那么程序还会自动链接,生成的文件默认为 a.out。

编译部分分为三个阶段:

  1. 预处理阶段

该阶段会修改或添加代码,预处理器(cpp)会根据以字符 # 开头的命令,修改原始的 C 程序。比如在程序中第一行为 #include <stdio.h>,那么该命令告诉预处理器读取头文件 stdio.h 的内容,并把它直接插入程序文本中。结果就得到另一个 C 程序,通常以 .i 作为文件扩展名。

指令如下:

    gcc -E hello.c -o hello.i
  1. 编辑阶段

该阶段是生成对象代码的实际编译过程,编译器(ccl)将 .i 文件翻译成文本文件(文件扩展名为 .s),它包含一个汇编语言程序

在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。用户可以使用“-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。汇编语言是非常有用的,它为不同高级语言不同编译器提供了通用的语言。

如:C 编译器和 Fortran 编译器产生的输出文件用的都是一样的汇编语言。

指令如下:

gcc -S hello.i -o hello.s

hello.s 文件内容如下:

          .file "hello.c"
          .section  .rodata
  .LC0:
          .string   "hello,world"
          .text
          .globl    main
          .type main, @function
  main:
  .LFB0:
          .cfi_startproc
          pushq %rbp
          .cfi_def_cfa_offset 16
          .cfi_offset 6, -16
          movq  %rsp, %rbp
          .cfi_def_cfa_register 6
          leaq  .LC0(%rip), %rdi
          call  puts@PLT
          movl  $0, %eax
          popq  %rbp
          .cfi_def_cfa 7, 8
          ret
          .cfi_endproc
  .LFE0:
          .size main, .-main
          .ident    "GCC: (Ubuntu 7.2.0-8ubuntu3) 7.2.0"
          .section  .note.GNU-stack,"",@progbits
  1. 汇编阶段

接下来汇编器(as)将 .s 文件翻译成机器语言指令,把这些指令打包成一种叫做可重定位目标程序(relocatable object program)的格式,并将结果保存在 .o 文件中,该文件是一个二进制文件。

指令如下:

    gcc –c hello.s –o hello.o

3.3、链接

链接器(ld)将原代码文件中由编译器产生的各种对象模块组合起来,再从 C 语言提供的程序库中添加必要的代码模块,将他们组合成一个可执行文件。链接器也可以检测和报告错误。如果连接成功会产生一个可执行文件,在 Linux/Unix 环境下,该文件无扩展名。

指令如下:

gcc hello.o -o hello

以上几个步骤可以使用以下指生成可执行文件:

gcc -o hello hello.c

3.4、执行

经过以上几个步骤,hello.c 已经被编译系统翻译成成了可执行目标文件 hello,并被保存在磁盘上。在 Linux/Unix 系统下只要在终端输入可执行文件名就可以执行程序。

指令:

linux> ./hello
hello,world

以上步骤可以总结为下图:

源文件转化为目标文件.png

四、示例

使用前面的 hello.c 作为示例:

#include <stdio.h>

int main()
{
    printf("Hello world!\n"); // print
    return 0;
}

4.1、注释

C语言的注释分为两种:

  1. 以“//”开头的;

  2. 在“/** **/”之间的。

4.2、预处理指令

以下代码行:

#include <stdio.h>

严格来说他并不是可执行程序的一部分,但是它很重要,程序缺少它是不可以执行的。符号“#”表示这是一个预处理指令,告诉编译器在编译源代码之前,要先做些操作。以上介绍的编译过程的预处理阶段就是处理这些预处理指令的。预处理指令相当多,大多放在源程序文件的开头部分。

注意:在一些系统中,头文件名是不区分大小写的,但在 #include 指令中,这些文件名通常是小写的。

4.3、main() 函数

int main()
{
    printf("Hello world!\n"); 
    return 0;
}

每个 C 程序必须有一个 main() 函数 —— 每个程序都是由这个函数开始执行的。

五、预处理器

以上实例中展示了如何使用预处理指令 —— 把头文件的内容添加到源文件中。编译的预处理阶段做的工作远不止这些。除了指令之外,源文件还可以包含宏。宏是提供给预处理器的指令,来添加或是修改程序中的语句。

宏可以很简单,例如只定义一个符号:INDEX_FOOT,只要出现这个符号就使用 10 代替,如下所示:

# define INDEX_FOOT 10

宏也可以很复杂,根据特定条件可以将大量代码添加到源文件中,例如在 Android 的 Binder 中,c 层代码常使用宏添加代码到源文件中,代码如下所示:

#define DECLARE_META_INTERFACE(FregService)
    static const android::String16 descriptor;
    static android::sp<I##INTERFACE> asInterface(const android::sp<android::IBinder>& obj);
    virtual const android::String16& getInterfaceDescriptor() const;
    I##INTERFACE();
    virtual ~I##INTERFACE();

在 IFregService.c 中展开后:

static const android::String16 descriptor; // 描述接口名称
static android::sp<IFregService> asInterface(const android::sp<android::IBinder>& obj); // 将IBinder对象转化为IFregService接口
virtual const android::String16& getInterfaceDescriptor() const;
IFregService(); // 构造函数
virtual ~IFregService(); // 析构函数

参考

Beginning C
深入理解计算机操作系统

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容

  • TITLE: 编程语言乱炖 码农最大的烦恼——编程语言太多。不是我不学习,这世界变化快! 有时候还是蛮怀念十几、二...
    码园老农阅读 5,316评论 2 35
  • 妮妮/当我们不与生活苟且,会发生什么? 最近英国小伙Jack Morris火爆网络,当然不是因为他涉及到了韩国总统...
    龙妮妮阅读 1,428评论 0 4
  • 晚上习惯性刷微信文章,看到这样一段话“情商决定你能不能意识到别人不开心,而人品考验的是你想不想让别人不开心。大部分...
    言小胡阅读 135评论 0 0
  • 十四年,似乎足够冲淡一切,在文华东方酒店门前依旧一片花海,不知道人们还能坚持多少年,也许只要张国荣的歌曲和电影依旧...
    神枪工作室阅读 299评论 0 1
  • O 优美的环境、清新的空气、洁净的水源是人们实现美好生活的必备条件,特别是在经历过雾霾,在空气遭到污染的环境里生活...
    果果亲阅读 57评论 0 1