https://www.zhihu.com/people/jiu_sheng
https://blog.csdn.net/qianshang52013/article/details/138140235?spm=1001.2014.3001.5501
Autosar 系列教程:小柴带你学 AutoSar 总目录
# 小柴带你学 AutoSar 系列一、基础知识篇(3)C 语言基础
# C 语言入门基本语法
C 语言是一种功能强大且高效的编程语言,被广泛应用于系统编程、嵌入式系统、游戏开发等领域。本文将介绍 C 语言的基本语法,并通过代码示例帮助你理解和掌握这些基础知识。
# 1. 程序结构
一个简单的 C 语言程序通常包含以下几个部分:
- 预处理指令
- 主函数
- 变量声明
- 语句和表达式
以下是一个简单的 C 语言程序示例:
#include <stdio.h> // 预处理指令,包含标准输入输出库 | |
int main() { // 主函数 | |
printf("Hello, World!\n"); // 输出语句 | |
return 0; // 返回值,0 表示程序成功结束 | |
} |
# 2. 变量和数据类型
C 语言支持多种数据类型,包括整型、浮点型、字符型等。常见的基本数据类型有:
int
:整型float
:单精度浮点型double
:双精度浮点型char
:字符型
变量声明的示例如下:
int a; // 整型变量 | |
float b; // 浮点型变量 | |
double c; // 双精度浮点型变量 | |
char d; // 字符型变量 | |
a = 10; // 赋值 | |
b = 3.14f; // 赋值 | |
c = 2.718; // 赋值 | |
d = 'A'; // 赋值 |
# 3. 常量
常量是值在程序运行期间不可更改的数据。可以使用 const
关键字定义常量:
const int MAX_SIZE = 100; // 整型常量 | |
const float PI = 3.14159; // 浮点型常量 |
# 4. 运算符
C 语言提供了多种运算符,包括算术运算符、关系运算符、逻辑运算符等。
- 算术运算符:
+
,-
,*
,/
,%
- 关系运算符:
==
,!=
,>
,<
,>=
,<=
- 逻辑运算符:
&&
,||
,!
示例:
int x = 5, y = 3; | |
int sum = x + y; // 算术运算 | |
int diff = x - y; | |
int prod = x * y; | |
int quotient = x / y; | |
int remainder = x % y; | |
int isEqual = (x == y); // 关系运算 | |
int isGreater = (x > y); | |
int andResult = (x > 0 && y > 0); // 逻辑运算 | |
int orResult = (x > 0 || y < 0); | |
int notResult = !(x > 0); |
# 5. 控制结构
# 条件语句
条件语句用于根据条件的真伪执行不同的代码块。
if
语句:
int number = 10; | |
if (number > 0) { | |
printf("Number is positive\n"); | |
} else if (number < 0) { | |
printf("Number is negative\n"); | |
} else { | |
printf("Number is zero\n"); | |
} |
switch
语句:
char grade = 'B'; | |
switch (grade) { | |
case 'A': | |
printf("Excellent\n"); | |
break; | |
case 'B': | |
printf("Good\n"); | |
break; | |
case 'C': | |
printf("Fair\n"); | |
break; | |
case 'D': | |
printf("Poor\n"); | |
break; | |
default: | |
printf("Invalid grade\n"); | |
} |
# 循环语句
循环语句用于重复执行某个代码块。
for
循环:
for (int i = 0; i < 5; i++) { | |
printf("i = %d\n", i); | |
} |
while
循环:
int count = 0; | |
while (count < 5) { | |
printf("count = %d\n", count); | |
count++; | |
} |
do-while
循环:
int n = 0; | |
do { | |
printf("n = %d\n", n); | |
n++; | |
} while (n < 5); |
# 6. 函数
函数是组织代码的基本单元,用于实现特定功能。函数可以有参数和返回值。
函数定义和调用示例如下:
#include <stdio.h> | |
int add(int a, int b) { // 函数定义 | |
return a + b; | |
} | |
int main() { | |
int result = add(5, 3); // 函数调用 | |
printf("Result = %d\n", result); | |
return 0; | |
} |
# 7. 数组
数组是存储同类型数据的集合,可以通过下标访问数组元素。
数组声明和使用示例:
int numbers[5] = {1, 2, 3, 4, 5}; // 数组声明和初始化 | |
for (int i = 0; i < 5; i++) { | |
printf("numbers[%d] = %d\n", i, numbers[i]); | |
} |
# 8. 指针
指针是存储变量地址的变量,可以通过指针访问和操作变量的值。
指针示例:
int x = 10; | |
int *p = &x; // 指针 p 指向 x 的地址 | |
printf("Value of x = %d\n", x); | |
printf("Address of x = %p\n", p); | |
printf("Value at address p = %d\n", *p); // 通过指针访问 x 的值 | |
函数返回值类型 (* 指针变量名) (函数参数列表); | |
typedef 函数返回值类型 (* 指针变量名) (函数参数列表); | |
typedef void (*pFun)(int x); | |
void myFun(int x) | |
{ | |
printf("myFun: %d\n",x); | |
} | |
pFun = myFun;// 函数指针指向 myFun (); 调用:pFun (); |
# 9. 结构体
结构体是用户自定义的数据类型,用于存储不同类型的数据。
结构体定义和使用示例:
struct Student { | |
int id; | |
char name[50]; | |
float score; | |
}; | |
struct Student student1; | |
student1.id = 1; | |
strcpy(student1.name, "John Doe"); // 字符数组赋值需要使用 strcpy 函数 | |
student1.score = 95.5; | |
printf("ID: %d\n", student1.id); | |
printf("Name: %s\n", student1.name); | |
printf("Score: %.2f\n", student1.score); |
# 10. 共用体
共用体(Union)是 C 语言中一种特殊的数据类型,它允许在相同的内存位置存储不同的数据类型。与结构体不同的是,共用体的所有成员共享同一块内存空间,因此共用体的大小等于其最大成员的大小。
# 共用体的定义
共用体通过关键字 union
来定义,其语法如下:
union UnionName { | |
member1_type member1; | |
member2_type member2; | |
// 可以有多个成员 | |
}; |
# 共用体的使用
共用体的成员可以像结构体的成员一样被访问。但是,共用体的每次赋值都会覆盖之前的值,并且只能同时使用一个成员。
union Data { | |
int i; | |
float f; | |
char str[20]; | |
} data; | |
data.i = 10; | |
printf("data.i = %d\n", data.i); // 输出 10 | |
data.f = 3.14; | |
printf("data.f = %.2f\n", data.f); // 输出 3.14 | |
strcpy(data.str, "Hello"); | |
printf("data.str = %s\n", data.str); // 输出 Hello |
在上面的示例中,共用体 Data
有三个成员: i
、 f
和 str
,它们分别是整型、浮点型和字符数组类型。因为共用体的所有成员共享同一块内存空间,所以对一个成员的赋值会影响其他成员的值。
# 应用场景
- 节省内存:当某些数据共享同一块内存空间时,可以使用共用体来节省内存。
- 数据类型转换:在一些特定情况下,共用体可以用于进行不同类型之间的转换。
# 11. 宏定义
# 创建符号常量
宏定义可以用来创建符号常量,这些常量在程序中可以被多次引用,提高了代码的可读性和维护性。
#define PI 3.14159 | |
#define MAX_SIZE 100 |
在上面的示例中, PI
和 MAX_SIZE
都被定义为符号常量,它们在程序中可以被多次使用而不用重复书写其值。
# 创建代码片段
宏定义还可以用来创建代码片段,这些片段在程序中被多次调用。
#define SQUARE(x) ((x) * (x)) |
上面的宏定义创建了一个求平方的宏,可以通过传入参数 x
来实现平方操作。
# 示例
下面是一个使用宏定义的示例,演示了创建符号常量和代码片段的用法:
#include <stdio.h> | |
#define PI 3.14159 | |
#define MAX(a, b) ((a) > (b) ? (a) : (b)) | |
int main() { | |
printf("PI = %.2f\n", PI); | |
int x = 5, y = 10; | |
int max_value = MAX(x, y); | |
printf("Max value = %d\n", max_value); | |
return 0; | |
} |
在这个示例中, PI
被定义为符号常量, MAX
被定义为求最大值的宏。
# 12. 枚举
枚举是一种用户定义的数据类型,它允许为一组相关的常量赋予符号名称。这使得代码更易于阅读和维护。
enum Weekday { | |
Monday, | |
Tuesday, | |
Wednesday, | |
Thursday, | |
Friday, | |
Saturday, | |
Sunday | |
}; |
在上面的示例中,我们定义了一个枚举类型 Weekday
,其中包含了一周中的每一天。默认情况下,枚举常量的值从 0 开始,依次递增。
# 13. 递归
递归是指函数调用自身的编程技术。它在解决问题时通常将问题分解为更小的、类似的子问题,直到达到基本情况。
#include <stdio.h> | |
int factorial(int n) { | |
if (n <= 1) { | |
return 1; | |
} else { | |
return n * factorial(n - 1); | |
} | |
} | |
int main() { | |
int result = factorial(5); | |
printf("Factorial of 5 is %d\n", result); | |
return 0; | |
} |
在这个例子中, factorial
函数通过递归调用自身来计算给定数字的阶乘。
# 14. 内联函数
在 c/c++ 中,为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别的引入了 inline 修饰符,表示为内联函数。
栈空间就是指放置程序的局部数据(也就是函数内数据)的内存空间。
inline 仅是一个对编译器的建议
#include <stdio.h> | |
inline const char *num_check(int v) | |
{ | |
return (v % 2 > 0) ? "奇" : "偶"; | |
} | |
int main(void) | |
{ | |
int i; | |
for (i = 0; i < 100; i++) | |
printf("%02d %s\n", i, num_check(i)); | |
return 0; | |
} | |
/* | |
上面的例子就是标准的内联函数的用法,使用 inline 修饰带来的好处我们表面看不出来,其实,在内部的工作就是在每个 for 循环的内部任何调用 dbtest (i) 的地方都换成了 (i%2>0)?"奇":"偶",这样就避免了频繁调用函数对栈内存重复开辟所带来的消耗。 | |
*/ |
内联是以 ** 代码膨胀(复制)** 为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。
如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。
# C 语言关键字
C 语言中的关键字可以根据其功能和用途进行分类。以下是对 C 语言关键字的分类:
# 1. 数据类型声明
- char:用于声明字符型变量或函数的返回类型。
- int:用于声明整型变量或函数的返回类型。
- float:用于声明单精度浮点型变量或函数的返回类型。
- double:用于声明双精度浮点型变量或函数的返回类型。
- void:用于指定函数无返回值或无参数,或者声明指向未知类型的指针。
- long:用于声明长整型变量或函数的返回类型。
- short:用于声明短整型变量或函数的返回类型。
- signed:用于声明有符号整型变量。
- unsigned:用于声明无符号整型变量。
# 2. 变量声明和存储类别
- auto:用于声明自动变量,其生命周期随着代码块的结束而结束。
- static:用于声明静态变量,其生命周期在整个程序执行期间保持不变。
- extern:用于声明变量或函数是在其他文件中定义的。
- register:用于声明寄存器变量,提示编译器将变量存储在 CPU 寄存器中。
- const:用于声明只读变量,其值在初始化后不能修改。
- volatile:用于告诉编译器变量的值可能会在外部被改变,从而防止编译器对该变量进行优化。
# 3. 流程控制
- if:用于创建条件语句。
- else:用于在 if 语句中指定条件为假时要执行的代码块。
- switch:用于创建 switch 语句。
- case:用于在 switch 语句中指定不同的情况。
- default:在 switch 语句中用于指定默认情况。
- while:用于创建 while 循环。
- do:用于创建 do-while 循环。
- for:用于创建 for 循环。
- break:用于跳出循环或 switch 语句。
- continue:用于跳过循环中的当前迭代,继续下一次迭代。
- goto:用于无条件地转移到程序中的标记位置。
- return:用于从函数中返回值。
# 4. 函数和返回值
- void:用于指定函数无返回值或无参数,或者声明指向未知类型的指针。
- return:用于从函数中返回值。
# 5. 结构和组织代码
- struct:用于定义结构体类型。
- union:用于定义共用体类型。
- typedef:用于定义新的数据类型名称。
- enum:用于定义枚举类型。
# 6. 内存大小和类型检查
- sizeof:用于获取数据类型或变量的大小(字节数)。
# 7. 标记和标签
- goto:用于无条件地转移到程序中的标记位置。
- label_name::标签名称,通常与
goto
语句配合使用。
# 8. 条件编译
- #if:条件预处理指令,根据条件编译指定的代码。
- #ifdef:条件预处理指令,如果定义了指定的宏则编译后面的代码。
- #ifndef:条件预处理指令,如果未定义指定的宏则编译后面的代码。
- #elif:条件预处理指令,用于多个条件之间的选择。
- #else:条件预处理指令,用于条件不成立时执行的代码。
- #endif:条件预处理指令,结束条件编译块。
- #define:用于定义宏。
- #undef:用于取消已定义的宏。
- #include:用于包含其他文件的内容。
这些关键字和预处理指令在 C 语言中起着不同的作用,能够帮助程序员控制程序的流程、声明变量和类型、组织代码结构等。理解和熟悉这些关键字的用法是编写高效、可读性强的 C 代码的重要基础。
# C 语言运算符
C 语言中的运算符是用来执行各种数学和逻辑运算的特殊符号。它们可以用于操作各种类型的数据,包括整数、浮点数、字符等。以下是 C 语言中常用的运算符及其优先级:
# 1. 算术运算符
- +:加法运算
- -:减法运算
- *****:乘法运算
- /:除法运算
- %:取模运算(求余数)
# 2. 关系运算符
- ==:等于
- !=:不等于
- >:大于
- <:小于
- >=:大于等于
- <=:小于等于
# 3. 逻辑运算符
- &&:逻辑与
- ||:逻辑或
- !:逻辑非
# 4. 位运算符
- &:按位与
- |:按位或
- ^:按位异或
- ~:按位取反
- <<:左移位
- >>:右移位
# 5. 赋值运算符
- =:赋值运算符
- +=:加法赋值
- -=:减法赋值
- *=:乘法赋值
- /=:除法赋值
- %=:取模赋值
- &=:按位与赋值
- |=:按位或赋值
- ^=:按位异或赋值
- <<=:左移位赋值
- >>=:右移位赋值
# 6. 其他运算符
- sizeof():返回数据类型或变量的大小(字节数)
- ?::条件运算符(三目运算符)
- ,:逗号运算符(用于分隔多个表达式,返回最后一个表达式的值)
# 7. 优先级
运算符的优先级确定了它们在表达式中的执行顺序。以下是常见运算符的优先级,按照从高到低的顺序排列:
- ():圆括号(最高优先级)
- [], ->, .:数组访问、结构体和共用体成员访问
- ++, --:自增和自减
- +, -:正负号
- !, ~:逻辑非和按位取反
- sizeof:大小运算符
- *, /, %:乘法、除法和取模
- +, -:加法和减法
- <<, >>:左移位和右移位
- <, <=, >, >=:关系运算符
- ==, !=:等于和不等于
- &:按位与
- ^:按位异或
- |:按位或
- &&:逻辑与
- ||:逻辑或
- ?::条件运算符
- =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=:赋值运算符(最低优先级)
了解运算符的优先级和结合性是编写正确和高效的表达式的关键。0