嵌入式day02-C语言基础

标准C开发基础

1. C语言概述

1.1 计算机语言介绍

1.1.1 计算机语言分类

计算机语言的主要分为机器语言、汇编语言和高级语言,机器语言和汇编语言是低级语言,直接由硬件执行,而高级语言需要通过编译器或解释器翻译成机器语言才能执行。

1、机器语言

机器语言是以二进制代码表示的指令集合,是计算能直接识别和执行的代码指令。
机器语言的优点是占用内存少、执行速度快
机器语言缺点是难编写、难阅读、难修改、难移植。
2、汇编语言

汇编语言是将机器语言的二进制代码指令用简单符号(助记符)表示的一种语言。
汇编语言与机器语言本质上是相同的,都可以直接对计算机硬件设备进行操作,具有很高的代码执行效率。
使用汇编语言需要掌握计算机CPU原理,不能跨平台,并且汇编语言在程序编写时容易出现冗长,所以具有较高的出错率。
3、高级语言
高级语言将计算机内部的许多相关机器操作指令,合并后形成的高级程序指令,并且屏蔽了具体操作细节,这样大大简化了程序指令,使编程者不需要了解太多计算机原理就可以进行编程。
目前常见的编程语言(C、Java、Python、C++…)都是属于高级语言。
高级语言代码必须转换为机器语言以后才能被计算机识别和执行,按转换过程又可以分为编译型语言和解释型语言。

1.1.2 编译型语言和解释型语言

1、编译型高级语言:通过编译器将源代码编译成机器语言,然后由计算机执行。编译型语言通常比解释型语言更高效,因为编译器可以将代码优化成机器语言,减少内存占用和执行时间。常见的编译型语言包括 C、C++等。
在这里插入图片描述
2、解释型高级语言,不需要编译成机器语言,而是直接解释执行源代码。=。解释型语言的优点是实时性、灵活性强,缺点是代码执行效率略较低,常见的解释型语言包括 Python、JavaScript、Shell等。
在这里插入图片描述

1.2 C语言发展历史和主要特点

1.2.1 C语言的发展历史

比C语言更早的B 语言是在 1970 年由贝尔实验室的 Richard B. Cook 和 William A. Shaw 开发的,它是为 UNIX 系统而设计的。
C 语言则在 1973 年由 Dennis Ritchie 在贝尔实验室开发,并于同年引入类型和结构化控制。1978 年,Knuth 和 Ritchie 合著的《The C Programming Language》出版,该书成为C 语言发展的里程碑,标志着 C 语言开始走向世界。

1、1989 年,ANSI 美国标准委员会发布了 C 语言的首个标准,即 C89 标准。

2、1990 年,对C89标准进行了修订,形成了 C90 标准。

3、1999 年,ISO 国际标准化组织发布了 C 语言的第三个标准,即 C99标准。

1.2.2 C语言主要特点

C 语言是一种非常强大和灵活的高级编程语言,适用于需要高效、灵活、可移植和底层的系统开发,例如操作系统、嵌入式系统、游戏开发等。

1、高效性:C语言代码执行速度非常快,因为它是一种编译型语言,将源代码编译成机器码后运行。

2、灵活性:C 语言允许程序员对内存进行直接操作,因此在编写底层系统和嵌入式系统时非常有用。

3、可移植性:C 语言代码可以在多个平台上编写和编译,因此它是一种跨平台的编程语言。

4、强大的控制结构:C语言具有强大的控制结构,例如条件语句、循环语句和函数调用等,使得它可以处理各种任务。

5、代码简洁:相对于其他的传统编程语言,C 语言的代码比较简洁。

6、库支持:C语言有大量的标准库和第三方库可供使用,可以大幅缩短开发时间。

7、内存管理:C语言程序员需要手动管理内存,这也使得它对于内存敏感的任务非常有用,例如游戏开发和资源受限的嵌入式系统开发。

1.2.3 C语系

C语言是目前90%语言的基础,很多语言都是由C语言发展变化而来,因此形成了C语系。C语言因此也被称为母体语言,常见基于C语系的高级语言有:

C++
Java
Python
C#

1.2.4 C语言的优缺点

1、优点

高效
可移植
功能强大
灵活、限制少
2、缺点

更容易隐藏错误
有时会难以理解
有时会难以修改

1.3 我的第一个C语言程序

1.3.1 C语言的开发周期

从代码编写到运行测试,C语言的完整开发周期如下:

1、编辑:编写源程序,在编辑窗口中编写 C 语言代码,例如使用Vi编写hello.c,编写完成后保存并关闭文件

2、预处理:处理包含的头文件和宏指令,如 #include

3、编译和汇编:检查代码语法,生成二进制的目标文件,如hello.o

4、链接:将多个目标文件和库链接成一个可执行程序,如a.out

5、载入:将可执行文件读入内存,形成进程映像,它包含可执行文件的所有代码、数据和堆栈等

6、运行:处理器从main 函数开始执行进程映像中的代码

1.3.2 “#include”指令

#include 指令用于包含头文件信息,它在预处理过程中会将头文件中的内容和当前文件的内容合并。C语言中可以通过双引号或尖括号两种方式包含头文件:

1、用<>包含的头文件,到标准头文件路径(usr/include)下寻找

2、用""包含的头文件,优先到当前目录下寻找

一般情况下,建议用<>包含标准头文件,用""包含自定义头文件。如果头文件既不在当前目录下,也不在标准头文件路径中,可以通过GCC编译器的“-I”选项告诉编译器到哪里寻找这样的头文件。

1.3.3 C语言程序的注释

在 C 语言中,注释的使用是非常重要的,它可以让读者更好地理解代码的含义和功能,同时也可以帮助程序员快速找到代码中的问题,具体分为多行注释和单行注释两种方式:

1、多行注释:以“/”开始,以“/”结束,中间的部分为注释,没有行数限制,但不能嵌套。

int main() {  
    /*  这里可以写多行注释,9
没有行数限制
但不能嵌套
 */  
    printf("Hello, World!");  
    return 0;  
}

2、单行注释:从“//”开始到本行末尾是注释。

int x = 10;  // 这里可以写单行注释,用于说明 x 的值是 10  

1.3.4 C语言编码规范

规范C编码风格可以使代码更加健壮、可读性更高,同时也能够提高代码的可维护性和可扩展性,并可以减少代码出错率,对于初学者可以先掌握一些最基本的规范:

1、语句尽量分在多行中书写

int main (void) {printf ("hello word"); return 0;} // 不好
int main (void) { //分成多行书写,更清晰
    printf ("hello world\n");
    return 0;
}

2、适当地使用空格、缩进和空行

空格可以使代码更加清晰
缩进可以增强代码的层次感
空行可以增强代码的逻辑性
3、合理地为标识符命名

匈牙利命名,如CreateWindow
下划线方式,create_window

2 变量和数据类型

2.1 变量的定义

2.1.1 什么是变量

在 C 语言中,变量是在内存中分配的一个区域,用于存储数据的值。变量名用于标识和区分不同变量,并且通过变量名可以访问和修改变量的值。变量有类型和值,类型用于描述变量可以存储的数据类型,而值则是变量存储的数据。
在这里插入图片描述

2.1.2 变量的类型

C 语言是一种强类型语言,这意味着每个变量都有具体的类型,并且不同类型的变量在内存中占用的空间大小不同,C语言中变量基本类型如下:

1、char:字符型,占1个字节空间。

2、int:整型数,占4个字节空间。

3、float:单精度浮点数,占4个字节空间。

4、double:双精度浮点数,占8个字节空间。

2.1.3 变量的定义

C语言中定义变量必须显式地声明其类型,基本语法格式如下:

类型 变量名;   // 定义变量不进行初始化
类型 变量1, 变量2;  // 同时定义多个变量
类型 变量名 = 初值;  // 定义同时初始化

定义变量示例:

int a = 10;  // 定义变量a,初始化其值为10
int b; // 定义变量b但未初始化,其值不确定
2.1.4 输出变量的值

在C语言的标准库中提供了printf()函数可以方便地输出变量的值,基本的使用方法如下所示:

int x=10;
printf(%d”, x);
int x=10,y=20;
printf(%d,%d”,x,y);
其中“%d”表示格式化占位符号,输出时会用变量的值进行替换,不同占位符对应不同的数据类型,如下所示:

int%d
char%c
float%f
double%lf
字符串:%s

格式化占位符号要与变量定义的类型一致,否则可能会导致输出结果的错误。

2.1.5【案例】定义变量并输出

定义多个不同类型的变量,然后使用printf()函数输出他们的值。

示例:var.c

#include <stdio.h>
int main (void) {
    int a = 10;
    int b;
    int c = 20, d;
    printf ("a=%d,b=%d,c=%d,d=%d\n", a, b, c, d);
    float e = 1.23;
    double f = 4.56;
    printf ("e=%f,f=%lf\n", e, f);
    return 0;
}
2.1.6 变量名必须是合法标识符

定义变量时,变量的名字不能随意指定,必须满足以下的语法要求:

1、必须以字母或下划线开头

int abc; // ok
int _abc; // ok
int 2abc; // error !
int *abc; // error !

2、只能包含字母、下划线和数字,不能包含其他特殊字符

int a_2; // ok
int a-2; // error !

3、字母的大小写敏感

int a, A; // 两个变量

4、变量的名字不能与关键字冲突

int float; // error !

注:在Vi编辑器中,蓝色字体的标识符一般都是关键字,比如int、void、return等

5、外变量名字最好有意义,能够见名知意

int age;
float salary;
int max;
int ttt, zyu; // 不建议
2.1.7【案例】变量的标识符

以下变量的名字中,哪些是正确的,哪些是错误的?

int num;
int 1num; // error
int _num;
int void; // error
int my-name; // error
int num_123;
int NUM;

2.2 C语言数据类型

2.2.1 基本数据类型

C语言中变量的基本数据类型只有char、int、float和double四种,但可以在基本类型前面增加关键字(如unsigned、short、long等)的修饰,改变在内存中占用的空间大小和取值范围。

2.2.2 字符型char

在 C 语言中,字符类型char被视为整数类型,可以表示 ASCII 码表中的字符。在C 标准没有说明普通 char 类型是有符号还是无符号类型(大多数编译器默认char是有符号的),有符号整数类型的取值范围是 -128 到 127,可以通过“unsigned char”表示无符号字符型,取值范围是 0 到 255。

字符型变量的底层存储就是整数,对于字符而言存储的是该字符在ASCII表中的代码
字符常量通过一对单引号(‘’)表示
用printf显示字符的时候,如果用%c显示的是字符,如果用%d显示的就是ASCII码
示例:char.c

  #include <stdio.h>
  
  int main() {
      char c = 'A';
      printf("The value of c is %c\n", c);
      printf("The value of c is %d\n", c);
      return 0;
  }
2.2.3【案例】字符型char的定义和使用

用单引号和整数分别定义char类型变量,进行简单运算后打印。

 #include <stdio.h>
 int main()
 {
         char c = 'a';
         printf("%c\n", c);
         printf("%d\n", c);
         c = c + 1;
         printf("%c\n", c);
         printf("%d\n", c);
         c = 65;
         printf("%c\n", c);
         return 0;
  }
2.2.4 整型int

在 C 语言中,整数类型是一个非常重要的概念,用于表示整数类型的数据。整数类型可以分为有符号和无符号类型,其中 signed 表示有符号类型(默认),unsigned 表示无符号类型。

在 16 位机和 32 位机上,int 类型的表示范围不同,这是由于硬件平台的不同导致的。通常情况下,16 位机的 int 类型2字节,而 32 位机的 int 类型最为4字节。另外在 C99 标准中,增加了 long long int 和 unsigned long long int 两种 64 位整数类型。这些类型的大小和取值范围是根据编译器的不同而不同的,因此需要在编译时指定正确的类型。

整数有二进制、八进制、十进制和十六进制四种,在 C 语言中,整数的进制默认为十进制,但在Linux系统编程和嵌入式系统中,二进制和十六进制也是经常使用的,使用printf()函数可以指定格式化符号“%x”输出十六进制数字。

示例:int.c

 #include <stdio.h>
 int main()
 {
         int num = 100;
         printf("%d\n", num);  // 十进制
         printf("%x\n", num);  // 十六进制
         return 0;
 }
2.2.5 整型常数

在 C 语言中,整型常数可以分为有符号整型和无符号整型两种类型,常见的表示方式如下:

100:默认为int,十进制
100Llong
100LLlong long
100uunsigned int
100ULunsigned long
0100:八进制,64
0x100:十六进制,256
2.2.6 浮点型float和double

浮点数就是数学中的小数,C 标准并没有明确规定浮点数精度的范围。实际上,浮点数在计算机内部通常是用二进制数表示的,而不是精确的数值。因此,浮点数类型在计算机内部存储的都是近似值,而不是精确值,在C语言中提供三种浮点类型:

float:单精度,如1.23f
double:双精度, 如1.23
long double :扩展双精度,如1.23L
示例:double.c

#include <stdio.h>
  
  int main() {
      float x = 3.14159;   // 定义一个浮点型变量 x,值为 3.14159  
      printf("x = %f\n", x);   // 使用 printf 函数输出 x 的值  
  
      double pi = 3.1415926535;
      printf("pi = %.10lf\n", pi);
  
      return 0;
  }

当前Linux环境中,输出浮点数的默认精度是保留6位小数,可以通过格式化字符串修改精度,比如“%.10lf”表示保留10位小数,“%.2f”表示保留2位小数。

2.2.7 获取变量的内存大小

C语言变量在定义时就已经确定了所占内存的大小,对于系统开发工程师必须清楚地知道每个变量所占内存空间,如果某些复杂类型(比如复合数据类型)无法确定大小时,可以使用sizeof关键字获取。

sizeof看起来像一个函数,但其实是一个运算符,使用格式如下:

sizeof(类型)
sizeof(变量名)
sizeof(表达式)
注:sizeof只关心类型,只会分析括号中的类型的大小,不会对括号中的表达式进行运算。

示例:sizeof.c

 #include <stdio.h>
 int main()
 {
     int i;
     short int si;
     long int li;
     unsigned int ui;
     unsigned short int usi;
      unsigned long int uli;
      float f;
      double d;
      long double ld;
      char c;
      unsigned char uc;
  
      printf("int 型所占的字节数为:%ld\n", sizeof(i));
      printf("short int 型所占的字节数为:%ld\n", sizeof(si));
      printf("long int 型所占的字节数为:%ld\n", sizeof(li));
      printf("unsigned int 型所占的字节数为:%ld\n", sizeof(ui));
      printf("unsigned short int 型所占的字节数为:%ld\n", sizeof(usi));
      printf("unsigned long int 型所占的字节数为:%ld\n", sizeof(uli));
      printf("float 型所占的字节数为:%ld\n", sizeof(f));
      printf("double 型所占的字节数为:%ld\n", sizeof(d));
      printf("long double 型所占的字节数为:%ld\n", sizeof(ld));
      printf("char 型所占的字节数为:%ld\n", sizeof(c));
      printf("unsigned char 型所占的字节数为:%ld\n", sizeof(uc));
  
      printf("int 型所占的字节数为:%ld\n", sizeof(int));
      i = 5;
      printf("表达式 i = 10 所占的字节数为:%ld\n", sizeof(i = 10));
      printf("i = %d\n", i);
  
      return 0;
  }

2.3 变量的输入和输出

2.3.1 输出函数printf

标准输出函数printf()是C语言代码中使用最为频繁的一个函数,常用于打印调试、输出变量的值,在前面案例中我们已经多次使用它打印单个变量的值,另外也可以使用它同时打印多个变量或常量。

示例:printf.c

#include <stdio.h>
  int main() {
       int a = 10;
       float b = 20;
       printf("a = %d, b = %f, c = %lf\n", a, b, 3.14);
       return 0;
   }
2.3.2 输入函数scanf

标准输入函数scanf()的功能和printf()正好相反,可以通过终端获取用户输入的数据并保存到变量中,基本语法格式如下:

scanf(“格式化字符串”,&变量名);
其中格式化字符串和printf()函数相同,但要保证和变量的类型相同,并且注意要在变量名字前面加一个取地址符号“&”。

示例:scanf.c

  #include <stdio.h>
  int main (void) {
      int num = 0;
      printf("请输入一个整数:");
      scanf("%d", &num);  // 注意格式化字符串后面不要再加\n
      printf("num=%d\n", num);
      return 0;
  }
2.3.3 输入缓冲区

scanf 函数的输入缓冲区是用于存储从键盘输入的数据的。在 scanf 函数调用时,数据会先存储在输入缓冲区中,然后 scanf 函数将缓冲区中的数据读入程序的指定变量中。

当输入缓冲区中的数据被读入程序时,输入缓冲区中的内容会被清理,以便为新的输入做好准备。但是如果输入缓冲区中的数据类型和scanf函数的格式化字符串不匹配时,可能无法读走数据。这是因为 scanf函数在读取数据时需要匹配格式化字符串,如果格式字符串和输入缓冲区中的数据不匹配,scanf 函数将无法正确地将数据读入程序中。

因此,在使用 scanf 函数时,需要确保输入缓冲区中的数据类型和格式化字符串相匹配,以确保数据能够正确地读入程序中。如果连续使用scanf实现输入操作,为了避免因为某个输入错误影响到后面的输入操作,可以通过下面两行代码清理输入缓冲区。

scanf("%*[^\n]"); 
scanf("%*c");  
对于 "%[^\n]",它的作用是清除输入缓冲区中所有除换行符 "\n" 之外的字符。这是因为 "\n" 是一个换行符,它会将用户输入的下一个字符覆盖。使用 "%[^\n]" 格式化字符串可以将除了 "\n" 之外的字符都清除掉,以便 scanf 函数能够正确地读取用户输入的数据。

对于 “%*c”,它的作用是清除输入缓冲区中的换行符 “\n”。这是因为 “\n” 是一个换行符,它会将用户输入的下一个字符覆盖。使用 “%*c” 格式化字符串可以将换行符 “\n” 清除掉,以便 scanf 函数能够正确地读取用户输入的数据。

2.3.4【案例】输入和输出

分别定义int、char、float、doubles四个变量,然后使用scanf函数获取用户输入数据并保存到变量中,再使用printf函数将变量值打印出来。

示例:sp.c

#include <stdio.h>
int main (void) {
     int a;
     scanf ("%d", &a);
     scanf("%*[^\n]");
     scanf("%*c");
     printf ("a=%d\n", a);
     char c;
     scanf ("%c", &c);
     scanf("%*[^\n]");
     scanf("%*c");
     printf ("c=%c\n", c);
     float f;
     scanf ("%f", &f);
     scanf("%*[^\n]");
     scanf("%*c");
     printf ("f=%f\n", f);
     double d;
     scanf ("%lf", &d);
     scanf("%*[^\n]");
     scanf("%*c");
     printf ("d=%lf\n", d);
     return 0;
 }

3 进制转换

3.1 二进制

3.1.1 什么是二进制

二进制是计算技术中广泛采用的一种数制,因为数字计算机只能识别和处理由‘0’.‘1’符号串组成的代码。二进制数据是用0和1两个数码来表示的数。它的基数为2,进位规则是“逢二进一”,借位规则是“借一当二”。当前的计算机系统使用的基本上是二进制系统,数据在计算机中主要是以补码的形式存储的。计算机中的二进制其实是一个非常微小的开关,用“开”来表示1,“关”来表示0。

3.1.2 二进制整数

二进制中只能有0和1,不会出现2,因为逢2就进位。我们来看一下某个二进制的整数:

0101 1111
这个二进制数的最后一位的权重就是1,倒数第二位的权重是2,倒数第三位的权重是4,倒数第四位的权重是8,倒数第n位的权重就是2的n-1次方。

示例:0到15的二进制

0=0000 0000             9=0000 1001
1=0000 0001             10=0000 1010
2=0000 0010             11=0000 1011             
3=0000 0011             12=0000 1100
4=0000 0100             13=0000 1101
5=0000 0101             14=0000 1110
6=0000 0110             15=0000 1111
7=0000 0111             …… 
8=0000 1000

3.2 不同进制之间的转换

3.2.1 二进制转十进制

1、正数

对于二进制数转换为十进制数的方法,可以使用权重乘积相加的方法,比如:0101 1001,计算方法如下:

1*64+0*32+1*16+1*8+0*4+0*2+1*1 = 89

2、负数

对于有符号整数来说,第一位是符号位,0代表正数,1代表负数。二进制负数需要按位取反后加1,可以得到对应的正数,计算结果加上负号即可,比如:1111 1110计算方法如下:

先按位取反 -> 0000 00011            ->  0000 0010 (补码)
0000 0010 -> 对应正数是2,所以计算结果是 -2
3.2.2 十进制转二进制

1、正数

除以2取余,反向输出余数,除到0为止,比如计算整数89的二进制转换:

89÷2 余数1
44÷2 余数0
22÷2 余数0
11÷2 余数1
5÷2  余数1
2÷2  余数0
1÷2  余数1
反向输出余数可以得到: 0101 1001 (第一位符号位)

2、负数

先将负数对应的正数转换成二进制,然后对二进制数按位取反后加1即可,比如-2的二进制转换:

先将2转成二进制 -> 0000 0010
按位取反               -> 1111 1101
再加1                   -> 1111 1110
得到-2的二进制格式为:1111 1110
3.2.3 八进制和十六进制

可以把八进制和十六进制看作是对二进制的一种简写方式,八进制是将二进制 3 位一组的形式进行表示,通常用“0~7”来表示。十六进制是将二进制 4 位一组的形式进行表示,通常用“0~F”来表示。为了与十进制区别,通常在八进制数前加入“0”标记,而十六进制数前面加“0X”标记。

示例:二进制到八进制和十六进制的转换

二进制数  0101  1011 
         三个一组可以写成  01  011  011,八进制就是:0133
         四个一组可以写成  0101 1011,十六进制就是:0X5B

4 总结

1、计算机语言分类

计算机语言主要分为机器语言、汇编语言和高级语言三种
高级语言分为编译器和解释型两种

2、C语言的主要优点

高效:C 语言的代码执行速度非常快,因为它是一种编译型语言,将源代码编译成机器码后运行。
灵活:C 语言允许程序员对内存进行直接操作,因此在编写底层系统和嵌入式系统时非常有用。
可移植:C 语言代码可以在多个平台上编写和编译,因此它是一种跨平台的编程语言。
内存管理:C 语言提供了自动内存管理机制,程序员不需要手动管理内存。

3、变量的基本类型

char:字符型,占1个字节空间。
int:整型数,占4个字节空间。
float:单精度浮点数,占4个字节空间。
double:双精度浮点数,占8个字节空间。

4、常用的三个函数

输出函数printf()
输入函数scanf()
计算大小 sizeof() // 本质是运算符

5、常见的进制数字

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值