C编程系列记录

2021/6/19 22:27:10

本文主要是介绍C编程系列记录,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 一、Linux C编程一站式学习
      • switch语句
      • 理解return
      • 结构体
      • 编码风格
      • 调试工具gdb
      • 完整编译C过程
  • 二、vscode debug方法
  • 总结


一、Linux C编程一站式学习

参考这里Linux C

switch语句

等价于if/else,但会有更优化
case只能比较常量

switch语句可以产生具有多个分支的控制流程。它的格式是:

switch (控制表达式) {
case 常量表达式: 语句列表
case 常量表达式: 语句列表
...
default: 语句列表
}
  • case后面跟表达式的必须是常量表达式,这个值和全局变量的初始值一样必须在编译时计算出来。

  • 第 2 节 “if/else语句”讲过浮点型不适合做精确比较,所以C语言规定case后面跟的必须是整型常量表达式。

  • 进入case后如果没有遇到break语句就会一直往下执行,后面其它case或default分支的语句也会被执行到,直到遇到break,或者执行到整个switch语句块的末尾。通常每个case后面都要加上break语句

理解return

在有返回值的函数中,return语句的作用是提供整个函数的返回值,并结束当前函数返回到调用它的地方
在没有返回值的函数中也可以使用return语句,例如当检查到一个错误时提前结束当前函数的执行并返回。

结构体

编程语言中,最基本的、不可再分的数据类型称为基本类型(Primitive Type),例如整型、浮点型;
根据语法规则由基本类型组合而成的类型称为复合类型(Compound Type),例如字符串是由很多字符组成的。
有些场合下要把复合类型当作一个整体来用,而另外一些场合下需要分解组成这个复合类型的各种基本类型,复合类型的这种两面性为数据抽象(Data Abstraction)奠定了基础

在学习一门编程语言时要特别注意以下三个方面:

  • 这门语言提供了哪些Primitive,比如基本类型,比如基本运算符、表达式和语句。
  • 这门语言提供了哪些组合规则,比如基本类型如何组成复合类型,比如简单的表达式和语句如何组成复杂的表达式和语句。
  • 这门语言提供了哪些抽象机制,包括数据抽象和过程抽象(Procedure Abstraction)
struct complex_struct {
	double x, y;
};

struct complex_struct {
	double x, y;
} z1, z2;

struct complex_struct z3, z4;

struct complex_struct z = { 3.0, 4.0 };

  • 抽象
    组合使得系统可以任意复杂,而抽象使得系统的复杂性是可以控制的,任何改动都只局限在某一层,而不会波及整个系统。著名的计算机科学家Butler Lampson说过:“All problems in computer science can be solved by another level of indirection.”这里的indirection其实就是abstraction的意思。

编码风格

命名风格
标识符命名应遵循以下原则:

  • 标识符命名要清晰明了,可以使用完整的单词和易于理解的缩写。短的单词可以通过去元音形成缩写,较长的单词可以取单词的头几个字母形成缩写。总结出一些缩写惯例,例如:
org缩写
countcnt
blockblk
lengthlen
messagemsg
trans…x…
  • 内核编码风格规定变量、函数和类型采用全小写加下划线的方式命名,常量(比如宏定义和枚举常量)采用全大写加下划线的方式命名,比如上一节举例的函数名radix_tree_insert、类型名struct radix_tree_root、常量名RADIX_TREE_MAP_SHIFT等。

  • 全局变量和全局函数的命名一定要详细,不惜多用几个单词多写几个下划线,例如函数名radix_tree_insert,因为它们在整个项目的许多源文件中都会用到,必须让使用者明确这个变量或函数是干什么用的。局部变量和只在一个源文件中调用的内部函数的命名可以简略一些,但不能太短。尽量不要使用单个字母做变量名,只有一个例外:用i、j、k做循环变量是可以的。

  • 禁止用汉语拼音做标识符,可读性极差。

函数
每个函数都应该设计得尽可能简单,简单的函数才容易维护。应遵循以下原则:

  • 一个函数只是为了做好一件事情,不要把函数设计成用途广泛、面面俱到的,这样的函数肯定会超长,而且往往不可重用,维护困难。
  • 函数内部的缩进层次不宜过多,一般以少于4层为宜。如果缩进层次太多就说明设计得太复杂了,应考虑分割成更小的函数(Helper Function)来调用。
  • 函数不要写得太长,建议在24行的标准终端上不超过两屏,太长会造成阅读困难,如果一个函数超过两屏就应该考虑分割函数了。[CodingStyle]中特别说明,如果一个函数在概念上是简单的,只是长度很长,这倒没关系。。
  • 执行函数就是执行一个动作,函数名通常应包含动词,例如get_current、radix_tree_insert。
  • 比较重要的函数定义上侧必须加注释,说明此函数的功能、参数、返回值、错误码等。
  • 另一种度量函数复杂度的办法是看有多少个局部变量,5到10个局部变量已经很多了。

indent工具可以把代码格式化成某种风格

indent -kr -i8 main.c 

调试工具gdb

调试的基本思想仍然是“分析现象->假设错误原因->产生新的现象去验证假设”这样一个循环,根据现象如何假设错误原因,以及如何设计新的现象去验证假设

  1. 单步执行和跟踪函数调用
  2. 断点
  3. 观察点
  4. 段错误

完整编译C过程

  • 汇编与C
gcc main.c -g  # -g
objdump -dS a.out #objdump反汇编时可以把C代码和汇编代码穿插起来显示

要查看编译后的汇编代码,其实还有一种办法是gcc -S main.c,这样只生成汇编代码main.s,而不生成二进制的目标文件

gcc -S main.c
cat main.s

汇编程序的入口是_start,而C程序的入口是main函数

以前我们说main函数是程序的入口点其实不准确,_start才是真正的入口点,而main函数是被_start调用的

  • 编译连接详细过程,参考这里
#1. 预处理preprocess (# 加头文件,替换宏等)
gcc -E test.c -o test.i
#2. 编译compiling,生成汇编代码(仍然是文本)
gcc -S test.i -o test.s
#3. 汇编Assembling, 生成目标文件(二进制)
gcc -c test.s -o test.o
#4. 链接Linking,生成可执行文件(二进制)
gcc test.o -o test

gcc命令这些选项都可以和-o搭配使用,给输出的文件重新命名而不使用gcc默认的文件名(xxx.c、xxx.s、xxx.o和a.out)

二、vscode debug方法

参考这里

  • 安装插件c/c++
  • 选择c++ edit Configurations(json),会生成c_cpp_properties.json
  • Run and Debug,选择gcc调试,会生成launch.json

调试方法,添加断点(一般在每个函数入口处添加便于观察函数内部),Variables会看到变量的变化。

总结

提示:这里对文章进行总结:



这篇关于C编程系列记录的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程