C语言笔记-概述

学习笔记

C Primer Plus

第二章

  学习了C Primer Plus的第二章-C语言概述,我认为最贴切的题目应该是初步认识C语言。通过几个简单且完整的C程序说明了C语言应该是什么样的。同样,相比课堂的学习了解到了更多的细节。期待明天第三章的内容和更好的自己。

一段简单的C源代码

//addForInt.c  在C99标准下,计算两个整数数字之和,并打印输出。

#include <stdio.h>
int add(int x1, int x2);

int main(void)
{
	/*
	 * a代表待相加的第一个数字
	 * b代表待相加的第二个数字
	 * result代表相加的结果
	 */
	int a, b, result;

	a = 10;
	b = 15;
	result = add(a, b);
	printf("%d+%d=%d", a, b, result);

	return 0;
}

/*
 * 对两个整数数字相加,并返回二者的和
 * x1代表待相加的第一个数字
 * x2代表待相加的第二个数字
 */
int add(int x1, int x2)
{
	//整数数字相加的结果
	int result;

	result = x1 + x2;

	return result;
}

为什么选择C99标准

  虽然现在有很多老式的编译器仍然仅能支持C89/C90标准,但是我认为C99确实是更加进步的,它增强了一些功能也添加了一些新的内容。要注意:

  1. 单行注释在C99之后(包括C99)才能使用。
  2. 空参数列表必须写void。C90,C99和C11三个标准都表示会逐渐淘汰不写void的写法。

对C源代码的理解

  首行,采用单行注释的方式,注明本源代码的文件名为addForInt.c,并注明程序的目标。这不是强制规定,而是一种规范的写法。
  空行。表示文件名和程序目标注释结束,可以开始编写C程序的预处理代码了。这不是强制规定,而是一种规范的写法。
  #include 是一种预处理指令,也可以叫做引用,含义是“拷贝”后面的文件的内容并“粘贴”到此处。实际上#代表C预处理器(C Preprocessor,简称CPP,而非cpp),#加后面的字符构成一种预处理指令。<stdio.h> 代表头文件stdio.h。
  int add(int x1, int x2);代表声明一个函数原型,意思是告诉编译器要使用该函数。目前,在形式上我认为它区别于头文件。
  空行。表示预处理结束。
  int main(void)。整体叫做函数头。int代表返回类型为整型,结果返回给系统。main是函数名,代表主函数,所有C程序都必须从main函数开始执行,但是main函数不一定要作为第一个函数写在源文件当中。()代表这是一个函数。void代表参数为空。
  {和}代表函数体的开始和结束,包括声明和语句。C语言在函数体中可以用{}将多条语句合并为一个块。
  //和//代表多行注释的开始,中间可有任意行的注释。编译器会忽略它们。这个特性从C89标准开始一直都是支持的。注释的作用是告诉代码使用者变量的意义。
  int a, b, result;叫做声明(包括;),区别于语句。声明了三个变量。三个变量的类型是int,int是C语言中的关键字,关键字是语言的词汇,有特殊的含义,不可以用做标识符。*变量的名称和函数的名称都叫做标识符。*因此编译器会在计算机内存中开辟三个空间,而且这三个空间的数据类型就是int。如书中所写,声明就是把标识符与内存中特定的位置关联起来,同时确定了存储在这个位置的数据类型或信息类型。对于标识符,需要注意的是操作系统和标准库函数中的标识符大多以_或__开头,自己编写源文件的时候应该尽量避免这种命名方式。
  a = 10;b = 15;原文说这两条语句都是“赋值语句”。这个说法不妥,因为C标准中并没有“赋值语句”,只有赋值运算符。实际上这两句是表达式语句。更多关于语句的知识留在第5章学习。将右侧的数字赋值给左边的标识符,实际上是将右侧的数字赋值给了左边标识符关联的存储空间。
  result = add(a, b);调用add函数,从main函数将实际参数a和b传递给add函数。此时,程序的控制权交给了add函数,当add函数执行完毕,控制权交给main函数的下一行。add函数的返回值赋值给result。
  printf("%d+%d=%d", a, b, result);调用printf函数,无返回值。"和"之间的内容是准备打印到控制台的信息(字符串)。%提示程序在此处要打印一个变量,d代表这个变量的数据类型是10进制的整数类型。%d是一种占位符。a, b, result依次对应前面的占位符。
  空行。
  return 0;返回0给操作系统,并结束程序。
  int add(int x1, int x2){}是函数定义。


调试

英文叫做debug,bug指程序中的错误。错误包括语法错误和语义错误。语法错误是指正确的符号放在了错误的位置。语义错误是指意思错了。编译器根据c语言标准对语法进行严格检查,却无法检查出语义错误,因为语义错误并没有违反C语言的规则。


补充问题

  1. 预处理和预处理指令是怎么回事
    在编译器编译源文件之前,预处理器会对源文件进行文本处理,预处理器就是一个文本替换工具,而且预处理器不属于C编译器的一部分。#即代表了预处理器,#与后面的字符组成预处理指令,预处理器按照预处理指令进行预处理。需要注意的是#要么在行首,要么前面只能有空格符,不允许其他任何符号在#之前。比如#include <stdio.h>预处理指令,预处理器从系统库种找到头文件stdio.h,并复制该文件的内容替换这条预处理指令。在这里可以注意到预处理指令没有用;结尾,事实上只有语句用分号结尾。当然,还有更多的预处理指令,预处理指令也有更多的细节,这里不做探讨,只需要记住最关键的一点预处理指令作用是对源代码种的文本进行替换。
  2. 头文件与库文件是怎么回事,二者有什么关系
    头文件是各种函数和变量的描述而不是逻辑实现(实际代码),它只是帮助编译器正确地组织好我们的程序,链接器会在一个预编译的库文件中找到实际代码,进而把引用函数的实际代码导出来替换原有函数。
  3. 返回给系统的0有什么用,或者说系统接受到程序的返回值之后会怎么处理
    返回0代表程序正常退出。通常,返回非0代表程序异常退出。比如Windows系统接收到后就会结束可执行目标程序的上下文,就是结束程序所在的进程。计算机系统相关的笔记写在StudyNotes/ducs,以免写的太复杂。
  4. 程序具体是怎么开始的,又是怎么结束的
    研读《深入理解计算机系统》发现这个问题,很难回答,涉及到硬件知识和操作系统等。想要搞清楚,至少要花上两天的时间研读最专业的书籍。计算机系统相关的笔记写在StudyNotes/ducs,以免写的太复杂。
  5. 结合《深入理解计算机系统》再次总结-编译系统与编译流程
    编译系统包括四个部分,分别是:预处理器,编译器,汇编器,链接器。
    假设有源程序fmy.c
    编译流程:
      第一步,预处理器将文本格式的源程序(源文件)fmy.c预处理,即进行文本替换,不讨论具体细节。生成修改了的源程序fmy.i。
      第二步,编译器文本格式的将修改了的源程序fmy.i编译为汇编程序fmy.s。
      第三步,汇编器将文本格式的汇编程序fmy.s翻译为二进制的可重定位目标程序(机器代码)fmy.o,也叫目标文件。
      第四步,链接器将二进制格式的目标文件与我们的目标文件用到的已经预编译的标准库中的目标文件合并在一起,最终形成可执行目标文件,简称可执行文件。(按照C Primer Plus中的说法,链接器还会将系统的标准启动代码合并到可执行目标文件当中。)
发布了14 篇原创文章 · 获赞 0 · 访问量 719

猜你喜欢

转载自blog.csdn.net/qq_38878217/article/details/104738062