Linux C第一、第二章笔记

第一章

编译执行过程:

    1. 首先用文本编辑器写一个C程序
    2. 然后保存成一个文件,例如program.c(通常C程序的文件名后缀是.c),这称为源代码(Source Code)或源文件
    3. 然后运行编译器对它进行编译,编译的过程并不执行程序,而是把源代码全部翻译成机器指令,再加上一些描述信息,生成一个新的文件,例如a.out,这称为可执行文件,可执行文件可以被操作系统加载运行,计算机执行该文件中由编译器生成的指令

编译和解释相结合执行:

    1. 以Python为例,程序员写的源代码.py文件首先被编译成.pyc文件,称为字节码(Byte Code)
    2. 然后字节码被Python虚拟机解释执行。字节码是Python虚拟机的指令而非机器指令,所以它是平台无关的,如果把字节码文件从一种平台复制到另一种平台上,只要另一种平台也安装了Python虚拟机,即可运行这个字节码文件。

  1. 语法规则是由符号(Token)和结构(Structure)的规则所组成的。

Token的概念相当于自然语言中的单词和标点、数学式中的数和运算符、化学分子式中的元素名和数字。

结构是指Token的排列方式。

关于Token的规则称为词法(Lexical)规则,而关于结构的规则称为语法(Grammar)规则[插图]。

  1. 程序中的错误被叫作臭虫(Bug),而找到这些Bug并加以纠正的过程就叫作调试(Debug)。
  1. #include<stdio.h>

/* main : generate some simple output */

int main(void)

{

printf("Hello,world.\n");

return 0;

}

/* ... */结构是一个注释(Comment),其中可以写一些描述性的话,解释这段程序在做什么。注释只是写给程序员看的,编译器会忽略从/*到*/的所有字符,所以写注释没有语法规则。

#if 0

bund()

{

}

#endif

这也是一种注释方式,在gcc编译过程中是不包括的。(适合大段大段的注释)

printf语句的作用是把消息打印到屏幕上。注意语句的末尾以;号(Semicolon)结束,下一条语句return 0;也是如此。

int和main之间至少要有一个空格分隔开。include必须单独占一行。

C语言用{ }括号(Brace或Curly Brace)把语法结构分组,在上面的程序中printf和return语句套在main的{}括号中,表示它们属于main的定义。我们看到这两句相比于main那一行都缩进(Indent)了一些,在代码中可以用若干个空格(Blank)和Tab字符来缩进,缩进不是必需的,但这样使我们更容易看出这两行是属于main的定义,要写出漂亮的程序必须有整齐的缩进。

双引号是字符串字面值的界定符,夹在双引号中间的一串字符才是它的内容。

一个好的习惯是打开gcc的-Wall选项,也就是让gcc提示所有的警告信息,不管是严重的还是不严重的,然后把这些问题从代码中全部消灭。 gcc hello.c -Wall

用gcc -E Hello.c选项可以看到预处理之后、编译之前的程序,用cpp main.c命令也可以达到同样的效果,只做预处理而不编译, cpp表示C preprocessor。

  1. /*

*comment1

*main: generate some simple output

*/

头尾两行是注释的界定符(Delimiter)/*和*/,中间两行开头的*号(Asterisk)并没有特殊的含义,只是为了看起来整齐,这不是语法规则而是大家都遵守的C代码风格(Coding Style)之一。

注释不能嵌套(Nest)使用,就是说一段注释的文字中不能再出现/*和*/了。.

有的C代码中有类似// comment的注释,两个斜线(Slash)表示从这里直到该行末尾的所有字符都属于注释,这种注释不能跨行,也不能穿插在一行代码中间。

man hello.c可以查看当前输入的变量用法归属等参数。

第二章

转义字符

如果在字符串字面值中要表示单引号和问号,既可以使用转义序列\'和\?,也可以直接用字符'和?。双引号既可以用\", 也可以直接用字符",而要表示'和\则必须使用转义序列。

C语言规定了几个控制字符,不能用键盘直接输入,因此采用\加字母的转义序列表示。

\a是响铃字符,在字符终端下显示这个字符的效果是PC喇叭发出嘀的一声,在图形界面终端下的效果取决于终端的实现。

在终端下显示\b和按下退格键的效果相同。

\f是分页符,主要用于控制打印机在打印源代码时提前分页,这样可以避免一个函数跨两页打印。

\n和\r分别表示Line Feed和Carriage Return,这两个词来自老式的英文打字机。Line Feed是跳到下一行的意思;Carriage Return是回到本行开头的意思。

\t“水平制表符”简称为“制表符”或Tab。

转换说明占位符

printf("character: %c\ninteger:%d\nfloating point:%f\n",')',34,3.14);

小数在计算机术语中称为浮点数。float类型无法做到非常准确,要使float==0只能是让它约等于0。

printf中的第一个字符串称为格式化字符串(Format String),它规定了后面几个常量以何种格式插入到这个字符串中,在格式化字符串中%号(Percent Sign)后面加上字母c、d、f分别表示字符型、整型和浮点型的转换说明(Conversion Specification),转换说明只在格式化字符串中占个位置,并不出现在最终的打印结果中,这种用法通常叫作占位符(Placeholder)。

常量

字符常量(用char来保存)要用单引号括起来,例如'}','a','X',注意单引号只能括一个字符而不能像双引号那样括一串字符,字符常量也可以是一个转义序列,例如'\n',这时虽然单引号括了两个字符,但实际上只表示一个字符。特别的:'\ddd'也是一个字符常量,表示一个八进制,'xdd'表示的是一个十六进制的数。eg: '\015', '\x7f'等等。但'\018'是错的,因为八进制里只有0~7这几个量。不加单引号,以\或\x加八进制或十六进制数字表示,这种表示方式相当于把八进制和十六进制整数常量开头的0替换成\了。\027; \x8d等等。

字符可以是字符集中任意字符。但数字被定义为字符型之后就不能参与数值运算。如’5’和5是不同的。‘5’是字符常量,不能直接参与运算,而只能以其ASCⅡ码值(053)来参与运算。

字符串常量(数组来保存):双引号引起来的一个或多个字符。像"","a","anbhVHY", "nhb/n/013/018/0"等等。

标识常量(define):用标识常量#define定义一个常量:#define H 90

define不仅用于定义常量,也可以定义更复杂的语法结构,称为宏(Macro)定义。

在进行宏定义的时候,一定要给定义的量加括号,防止后续出现符号优先级的问题导致程序计算错误。

#define ADD (3+6)

也可以将宏定义为带参数的宏:#define MAX(a,b) ((a)>(b) ? (a):(b))表示a是否大于b,如果是则取a,否则取b(即取冒号后面的数)。

宏的使用会占编译时间较少,适合软件运行开发这种比较要求时间上的追求,但它不检查语法,只是单纯的宏体与宏名之间的替换。函数定义也可以完完全全代替宏定义,而且会比较准确更稳定,但需要的运行时间比较长,适合程序应用等不追求时间上的速度的。

define定义是在预处理阶段处理的,枚举(enum coordinate_type这个)是在编译阶段处理的。

变量

  1. 常量一般用大写,变量用小写。常量不能被赋值,是一个固定的数,不能改变;而变量可以被赋值。
  2. 变量的类型决定了它所占用存储空间的大小。例如以下四个语句定义了四个变量fred、bob、jimmy和tom,它们的类型分别是字符型、整型、单精度浮点型和双精度浮点型。

char fred;

int bob;

float jimmy;

double tom;

    1. char型占一个字节的存储空间,一个字节通常是8个bit。

unsigned char型:无符号数;signed char型:有符号数。

C标准的Rationale之一:优先考虑效率,而可移植性尚在其次。

ASCII码的取值范围是0~127,所以不管char型是有符号的还是无符号的,保存一个ASCII码都没有问题。一般来说,如果用char型保存ASCII码字符,就不必明确写是signed还是unsigned;如果用char型表示8位的整数,为了可移植性就必须写明是signed还是unsigned。

除了char型以外的这些类型如果不明确写signed或unsigned关键字都表示signed。

    1. int 型占四个字节的存储空间,即32个bit。

short int(简写short)、int、long int(简写long)、long long int(简写long long)等。

这些类型都可以加上signed或unsigned关键字表示有符号或无符号数。用这两个关键字修饰int型时,signed int和unsigned int可以简写为signed和unsigned。

整数常量可在末尾加u或U表示“unsigned”,加l或L表示“long”,加ll或LL表示“long long”,例如0x1234U、98765ULL等。

ILP32这个缩写的意思是int(I)、long(L)和指针(P)类型都占32位。

    1. 浮点型有float、double、long double,double是64个bit, float是32个bit.

科学计数法:尾数和指数之间用e或E隔开,例如314e-2表示314×10-2,注意这种表示形式基数是10。

浮点数也可以加一个后缀,例如3.14f、.01L,浮点数的后缀和类型之间的对应关系比较简单,没有后缀的浮点数常量是double型的;有后缀f或F的浮点数常量是float型的;有后缀l或L的浮点数常量是long double型的。

  1. 声明和语句类似,也是以;号结尾的,但是在语法上声明和语句是有区别的,语句只能出现在{}括号中,而声明既可以出现在{}中也可以出现在所有{}之外。
  2. 给变量起名有一定的限制,C语言规定必须以字母或下划线(Underscore)开头,后面可以跟若干个字母、数字、下划线,但不能有其他字符。例如这些是合法的变量名:Abc、__abc__、_123。

关键字:auto break case char cionst continue default do double else enum extern float for goto if inline int long register restrict return short signed sizeof static struct switch typedef union unsigned void voIatile while _BooI _CompIex _Imaginary

    1. auto : 默认,自动分配空间,自动回收空间。
    2. register : (建议型)寄存器类型。只能定义局部变量,不能定义全局变量;大小有限制,只能定义32位大小的数据类型,如double就不可以,寄存器没有地址,所以一个寄存器类型的变量无法打印出地址查看或使用。(由gcc来决定是否采用你的建议)
    3. static : 静态型,自动初始化为0值或空值,并值其变量的值有继承性。(初次调用是初始值,再次调用则继承上次调用之后的值)。(加上之后,各文件之间各自用各自的,不冲突)。
    4. extern : 说明型,意味着不能改变被说明的变量的值或类型。(加上之后其他文件也可以使用)
  1. 一般来说应避免使用以下划线开头的标识符,以下划线开头的标识符只要不和C语言关键字冲突都是合法的,但是往往被编译器用作一些功能扩展(比如第18.4节讲到gcc的__attribute__语法),C标准库也定义了很多以下划线开头的标识符留作内部使用,所以一般避免使用这种标识符,以免造成命名冲突。

赋值(Assignment)语句

    1. 等号不表示数学里的相等关系,和1+1=2的等号是不同的,这里的等号表示赋值。

char firstletter;

int hour,minute;

firstletter = 'a';

hour = 11;

minute = 59;

    1. 定义一个变量,就是分配一块存储空间并给它命名;给一个变量赋值,就是把一个值保存到这块存储空间中。

上面的也可以写为:

char firstletter='a';

int hour=11,minute=59;

先定义一个变量再给它赋值”和“定义这个变量的同时将其初始化”所达到的效果是一样的。

变量名用在等号左边表示赋值,而用在printf中表示将其存储空间中的值取出来替换在它出现的地方。

printf (" Current time is %d:%d\n", hour , minute);

    1. 不同类型的变量所占用的存储空间大小是不同的,数据表示方式也不同,变量的最小存储单位是字节(Byte),在C语言中char型变量占一个字节。

表达式

  1. 在任意表达式后面加个分号也是一种语句,称为表达式语句。

如:hour*60+minute;

等号的优先级比+和*都低。

int total_minute;

total_minute=hour*60+minute;

如果一个表达式中出现多个等号,不是从左到右计算而是从右到左计算

int total_minute,total;

total=total_minute=hour*60+minute;

如果一个操作数的左右两侧各有一个相同优先级的运算符,这个操作数与左边的运算符结合还是与右边的运算符结合取决于运算符的结合性(Associativity),相同优先级的运算符应该具有相同的结合性,+ -和* /是左结合的,而等号是右结合的,所以在上面的表达式中totaI_minute和右边的等号结合,相当于totaI = (totaI_minute = hour * 60 + minute)。

较复杂的语句:

printf("%d:%d is %d minutes after 00:00\n",hour,minute,total_minute=hour*60+minute);

目前学的只有变量可以做左值,表达式所表示的存储位置称为左值(lvalue),允许放在等号左边,而以前我们所说的表达式的值也称为右值(rvalue),只能放在等号右边。

运算符

  1. 除法运算:

向下取整的运算称为Floor,向上取整的运算称为Ceiling。

在C语言中整数除法取的既不是Floor也不是Ceiling,无论操作数是正是负,总是把小数部分截掉,在数轴上向零的方向取整(Truncate towardZero)。或者说当操作数为正的时候相当于Floor,当操作符为负的时候相当于Ceiling。

#include<stdio.h>

int x,s;

int main()

{

x=17;

s=4;

printf("%d\n",x/s);

return 0;

}

运行结果为4

printf("%c\n",'a'+1) 运行结果是b.

  1. 关系运算符和相等性运算符

    1. 在C语言中“=”是赋值运算符;==表示数学中的相等关系,相当于数学中的“=”。
    2. 如果表达式所表示的比较关系成立则值为真(True),否则为假(False),在C语言中分别用int型的1和0表示。
    3. ==和!=称为相等性运算符(Equality Operator),其余四个称为关系运算符(Relational Operator),相等性运算符的优先级低于关系运算符。
  1. 在C语言中,一个单独的分号表示一条空语句(Null Statement)。
  2. 由{}括起来的若干条语句或声明组成的语句块(Statement Block)。{}是语句块。

void foo(void)

{

        int i=0;

        {

                int i=1;

                int j=2;

                printf("i=%d,j=%d\n",i,j);

        }

        printf("i=%d\n",i);

}

语句块中的变量i和函数的局部变量i是两个不同的变量,因此两次打印的i值是不同的;语句块中的变量j在退出语句块之后就没有了,因此最后一行的printf语句不能打印变量j,否则编译器会报错。

  1. 自增自减:运算符在前,先进行计算,再取变量值使用;变量在前,先取变量值使用,在进行计算。

i++ : 先取 i 使用,再 i = i+1;

++i : 先 i = i+1 使用,再 i 。

int main()

{

int i = 1, j = 10, value;

value = i++ + ++j; /* i , j=j+1, value = i+j ; i = i+1*/

printf("i = %d\n",i);

printf("j = %d\n",j);

printf("value = %d\n",value);

exit(0);

}

结果是 i = 2 ; j = 11 ; value = 12

a += 1表示 a = a+1;

b *= 3 表示 b = b*3;

真值为 1 ,假为 0 。

  1. 条件运算符:(?:)三目运算符,不太推荐嵌套。

a > b ? a : b ;

相当于:if ( a > b )

return a;

else

return b;

  1. 求字节数:

sizeof 运算符:

    • sizeof(表达式) // 可以没有括号,与return(1)的括号一样不起作用
    • sizeof(类型名) // 括号必须有
    • sizeof i++中的i++不求值,只是求表达式i++类型所占的字节数。printf("%d\n",sizeof(int));

printf("%d\n",sizeof(double));

结果为4 8

typedof 类型声明:

这个关键字用于给某种类型起个新名字。

typedef char array_t[10];

array_t a ; 这相当于声明char a[10]。

类型名也遵循标识符的命名规则,并且通常加个_t后缀表示Type。

  1. 位运算符:(以二进制位为单位进行运算)

<< 左移 >> 右移 (右移左补零,左移右补零)

int i = B1100 = 12 (8421法)

i >> 1 结果为 110 = 6

i << 1 结果为 1100 = 12

在一定的取值范围内,将一个整数左移1位相当于乘以2。eg:二进制11(十进制3)左移一位变成110,就是十进制的6,再左移一位变成1100,就是十进制的12。

在一定的取值范围内,将一个整数右移1位相当于除以2,小数部分截掉。

~ : 取反

~i 结果为 B0011

&:按位与 |:按位或

int i = B1100;

int j = B1001;

i | j 即 B1101

i&j 即 B1000

^:异或 (相同为0,不同为1)

i^j 即 B0101

一个数和自己做异或的结果是0。

x ^ x ^ y == y,因为x ^ x == 0,0 ^ y == y。

如果a1 ^ a2 ^ a3 ^ … ^ an的结果是1,则表示a1、a2、a3…an之中1的个数为奇数个,否则为偶数个。这条性质可用于奇偶校验(Parity Check)。

将操作数中第n位置1,其他位不变:num = num | 1<< (n);(位数从最低位开始数,且n从0开始数)

将操作数中第n位清0,其他位不变:num = num & ~(1 << n);

测试第n位为真假:if ( num & 1<<n)

‘0’ 的ASCII码 48,‘A’ 的ASCII码 65,‘a’ 的ASCCII码 97

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值