深圳幻海软件技术有限公司 欢迎您!

C语言该怎么进阶?你学会了吗?

2023-02-28

​C语言的入门还是很简单的:复制#include<stdio.h>intmain(){printf("helloworld\n");return0;}1.2.3.4.5.6.把这段代码输入文本编辑器vim,保存成hello.c文件:文件里的符号全是英文字符,别把分号打成中文字符。然后用g

​C语言的入门还是很简单的:

#include<stdio.h>
int main()
{
printf("hello world\n");
return 0;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

把这段代码输入文本编辑器vim,保存成hello.c文件:文件里的符号全是英文字符,别把分号打成中文字符。

然后用gcc编译器它,命令为:gcc hello.c

获得一个可运行的a.out文件,在命令行里直接运行它:./a.out

可以看到打印的hello world字符串。

如果gcc编译出来的a.out文件没有自动加执行权限,可以自己加上,命令为:

chmod +x a.out

初学者在这段代码里出的错误,基本都是忘了打结尾的分号,或者使用了中文字符而导致的。

学会了这段代码之后,C语言就可以算入门了。

这段代码虽然很短,但涉及到了头文件、宏、函数、字符串/数字 常量、return 语句,涵盖了C语言50%的常用语法吧​

剩下的语法,就是一些运算符、if else、while for、switch case等语句类型。

1.C语言入门阶段的最后一关,是指针。

指针,是一个表示变量的内存地址的无符号整数,位数跟CPU的字长相同。

64位机上,指针是8个字节。

老式的32位机上,指针是4个字节。

指针的字节数,跟long类型的整数一样。

int a[10];
int * p = a;
  • 1.
  • 2.

数组的指针,指的是数组的“首地址”:数组的第0号元素的内存地址。

C语言从0开始编号,数组元素的内存地址与它的编号一一对应:

&a[i] == (unsigned long)a + i * sizeof(a[0]);

所以,指针是一个unsigned long型的(无符号)整数。

指针变量,是一个保存某种类型的数据的内存地址的变量。

指针的类型,是它指向的数据的类型。

指针的++和--运算,一次跳过(它指向的)1个元素的字节数:int型指针++和--的变化是sizeof(int)个字节。

大多数系统上,sizeof(int) == 4.

2.C语言的文件读写,是关系到操作系统的。

C语言的文件函数

上图是C语言的文件函数,下图是Linux的文件函数。

C语言标准库的文件函数,最终也是使用OS的系统调用(其他语言的标准库也一样)。

操作系统为了把功能提供给应用层,都有一套API:其中的重点就是文件和网络编程的API。

API这个词来自windows,Linux上一般叫系统调用(syscall)。

Linux的文件函数

windows有它自己的应用编程框架(C#,VS),windows上的C语言都是通过VC++支持的:VC++,VS里的C++​

现在,C语言的应用编程,主要还是在Linux上。

Linux的系统调用,是C程序员在学会了基础内容之后,下一个阶段要熟悉的。

Linux继承的是Unix,它的API和Unix的区别不大:

要熟悉Linux系统,最好的参考资料还是那本老书:Unix环境高级编程​

这本书的作者理查德-史蒂文斯1999年就过世了,但他的书依然是最好的Linux编程书。

当然,最主要的参考资料还是Linux的man手册:在命令行里输入man open,就可以打开open()函数的手册,里面有open()函数的详细用法。

把man open换成man socket,就可以打开socket函数的手册。

对同一个词的介绍,在man手册里可能有好几页:一个是对同名的Linux命令的介绍,另一个是对同名的Linux函数的介绍。

如果直接man open打开的不是函数介绍,可以用man 2 open,或者man 3 open等,通过数字去选页数。

3.Linux的常用函数:

1)open, close, read, write, fcntl

这些都是跟文件相关的函数,作用跟函数名一样。

fcntl:可以给文件加锁,给socket设置非阻塞,用法比较复杂,可以参考man手册。

2)lseek

移动文件指针到哪个位置,用法跟C库的fseek一样。

3)socket, bind, listen, accept, connect, send / recv, sendto / recvfrom

这些都是网络编程的API,

socket:创建socket描述符,即网络文件的句柄。

Linux上一切都是文件,socket也被看做一个文件。

bind:绑定socket到某个IP和端口号。

listen:让socket进入监听状态,用于服务器端监听某个IP和端口号。

accept:用于服务器端接受用户的连接。

connect:用于客户端连接到服务器。

send / recv:TCP协议的数据发送和接收。

sendto / recvfrom:UDP协议的数据发送和接收。

关闭socket,也是使用close()函数。

4)epoll_create, epoll_wait, epoll_ctl

Linux的epoll异步事件机制,

用于同时监控多个socket网络连接的读写状态,并进行高并发的异步处理,它是网络服务器的核心函数。

俄罗斯人写的Nginx服务器,底层就是这3个函数。

nginx

5)setsockopt / getsockopt

设置或读取网络socket的状态,细节参考Linux man手册。

getsockopt的其中一个应用就是,它在异步连接时用于读取连接的错误码:相当于connect()函数的返回值,只是这个过程在异步获取的。

6)fork / execve

fork:以当前进程为蓝本,创建一个子进程。

execve:给当前进程加载一个新的可执行程序,并替换它的用户内存空间。

在多进程编程里,这2个是基本的函数,但一般并不常用。

多进程的网络服务器Nginx,就是用fork()创建多个进程的。

7)pthread_create

Linux上的pthread线程库的函数,用于在当前进程里创建一个线程。

pthread系列函数,也是一组跟多线程编程的函数。

4.汇编语言

不会汇编语言的C程序员,不是好程序员​

实际上,想学明白C语言的话,还是要学汇编语言。

不会汇编语言的话,像全局变量、局部变量、动态库、内存、操作系统这些跟C语言有关的东西,也是很难学明白的。

C语言,既是个大号的汇编语言,又是个OS的应用层胶水。

C语言,既离不了汇编语言,也离不了OS。

汇编语言就3个关键:内存、寄存器、栈。

这条汇编代码运行之前,内存什么状态、寄存器什么状态、栈是什么状态?

这条汇编代码运行之后,内存什么状态,寄存器什么状态,栈是什么状态?

记住这6个状态,也就学会了汇编语言了。

5.算法

算法关系到数学,算法导论是最好的参考资料。

当然,数学越好,越容易学算法。

但OpenCV开源之后,大多数情况下,用不到自己写算法​

跟图像处理、视觉识别相关的算法,OpenCV几乎都有。

算法工程师做的,更多是把这些基础算法整合成一个特定场景的识别模型。

6.图形界面

C语言可以选各种图形界面库,例如GTK,SDL,QT,etc.

想做界面程序的话,选一种自己看着顺眼的图形库,然后熟悉一下它的C语言API就行了。

一般来说,图形库的API都是支持多种语言的,C语言也是其中之一。