Administrator
发布于 2025-05-14 / 20 阅读
0
0

C2

数据类型和头文件

  • 基本数据类型

    • 数值型(short,int,long,long long ,float,double)

      • //位运算将char,unsigned char,short等自动提升到int或unsigned int进行位运算(称为整形提升) java c++都会进行整形提升

      • //例如 short a=10; short b=11; short c=a+b;当执行c=a+b时,a和b都会转成int,计算后转为short给c

    • char|str 字符串(结尾为\0)

      • char name[]="me33";

      • char name2[5]="me";//为 m e \0 \0 \0 即其他被填为\0

      • strlen(name) //返回4,只返回可见字符长度

    • 数组

      • int data[2]={1,2}; // int data[2][3];

      • 数组名就是数组第一个元素的地址;

  • 特殊数据类型

    • 枚举

      • enum color{red,blue,green,white,black}; //本质是int,例如blue=1

      • enum color c1=blue; if(c1==blue){}//赋值,判断

    • 指针

      • 指针+n:是取下n个存储单元的地址;指针-n;指针比较

      • &var //获取var的地址

      • int *pData; //申明指向int数据类型的指针变量

      • *pInt //获取pInt对应的变量,放表达式左边为赋值,放表达式右边为获取值

      • 结合优先级:括号() > 数组[]>指针* > 其他数据类型 参考下方代码块

      • 看一个指针的类型,直接把指针的名字去掉,剩下的就是指针的类型。参考下方代码块

      • 要知道指针所指向的类型,把指针的名字和*去掉,剩下的就是指针所指向的类型。注意优先级。参考下方代码块

      • 参考链接: https://www.cnblogs.com/mokongking/p/17329296.html

    • 结构体(结构名只是结构体的名称,&才能获取其地址)

      • struct Student{ char name[100]; int age;}; //结构体定义

      • struct Student s1;//声明结构体变量

      • printf("%s",s1.name); s1.name="cj"; //结构体的使用 或者 struct Student s2={"cj",12};进行初始化

      • 结构体指针

        • struct Student *sp=&s1;

        • 使用: (*bookp).name bookp->name 两种方式

        • 传递结构体或者结构体指针给函数,或者作为函数返回值,可以用const修饰来保护原始数据;且只是传递结构体的副本而已;当然可以传递结构体的地址给函数

    • 1.#define 宏 值 //数字常量,字符串常量,表达式等;一旦找到宏,会被值替代;

      • #define SQUARE(X) (X)*(X) 可以为类函数宏

      • //函数宏用括号包含,避免产生副作用

      • #define DllExport __declspec( dllexport ) //宏定义,定义导出的函数或类

        • class DllExport CameraSp{} //导出CameraSp类

        • int DllExport addTwo(int a,int b)//导出函数

    • 2.#include "" // #include <>

      • <>用于系统头文件,一般到保存系统标准头文件的位置查找头文件

      • “”用于自定义的头文件,先在当前目录查找头文件,然后去系统头文件目录查找

      • cpp文件引用c编写的头文件时,需要extern "C" { #include <libavformat/avformat.h> } 否则可能找不到符号

    • 3.条件编译

      • #ifndef,#ifdef,#else,#endif

    • 4.typedef

      • typedef long long JLong;

      • typedef const double *(*fp)(const double *,int) //将fp简化,fp是个指向函数的指针,是个类型名称;把fp拉到最后容易理解

      • typedef提供别名而已

				#ifdef MAVIS
					#include "s1.h"
					#define COUNT 10
				#else
					#include "s2.h"
					#define COUNT 20
				#endif
				如何保证头文件中的标识符唯一:
					例如xx.h
					#ifndef XX_H
						define _XX_H
						.....
					#endif
int p; // p是一个普通的int型变量
int *p; // p先与*结合,后与类型结合,所以p是一个指针,指针指向的内容是int型
int p[3]; // p先与[]结合,然后与类型结合,说明p是一个数组,数组里面的内容是int型
int *p[3]; // p先与[]结合,说明p是一个数组,然后再与*结合,说明数组p里面存放的是指针,然后与类型结合,说明指针指向的内容是int型,p是一个由返回整型数据的指针所组成的数组
int (*p)[3]; // ()的优先级最高,(*p)说明p是一个指针,然后与数组[3]结合,说明指针指向的是大小为3的一个数组,然后与类型结合,说明指针所指向的数组里面的内容为int型,p是一个指向由整型数据组成的数组的指针
int **p; // p先和最近的*结合,说明p是一个指针,然后再与剩下的*结合,说明指针p指向的是一个指针,然后与int结合,说明指针p所指向的指针(*p)所指向的内容(**p)为int型
int p(int); // p先于(int)结合,说明这是一个函数,函数的参数为int型,然后与外面的int结合,说明函数返回的内容是int型
int (*p)(int); // ()的优先级最高,(*p)说明p是一个指针,然后与(int)结合,说明指针所指向的内容是函数,函数的参数为int型,然后与外面的int结合,说明指针p所指向的内容(*p)是一个函数,该函数的返回内容为int型
int *(*p(int))[3]; // 一层一层的剥开,p首先与(int)结合,说明p是一个函数(这里说了p是一个函数),函数的参数为int型,然后与*结合,说明函数返回的是一个指针,然后与数组[3]结合,说明是返回的指针指向的是一个数组,然后与*结合,说明数组里面的内容是指针,然后与外面的int结合,说明数组里面的指针指向的内容是int型。所以p是一个参数为int型并且返回的是一个指向内容为int*型的数组的函数,由于int*是指针,指针指向的内容为int型,所以p返回的就是一个指向内容为指向内容为int型的指针的数组的函数(太绕了,注意段句)



int *(*p(int))[3]; // 这个过于复杂,再来一遍
// 括号里面的内容是一个整体,直接把(*p(int))替换为ptr,那么表达式就变成了
int *ptr[3]; // 这就简单多了,通过上面的例子可以知道,ptr是一个数组,数组里面的内容为指针,指针指向的内容为int型,即ptr是一个内容为指向内容为int型的数组
*p(int); // 同样通过上面的例子可以知道p是一个函数,函数的参数为int型,函数的返回内容是指针
// 下面就把他们结合起来
int *(*p(int))[3]; // p是一个函数,函数的参数为int型,函数的返回内容是一个指针,该指针指向的内容是一个数组,数组里面的内容为指针(该指针指向的内容为int型)



int p; // 去掉p,p是一个普通的int型变量
int *p; // 去掉p,说明指针的类型是int *型
int p[3]; // 去掉,说明p的类型为int [3],是一个普通的数组
int *p[3]; // 去掉p,说明指针的类型是int *[3]型
int (*p)[3]; // 去掉p,说明指针的类型是int (*)[3]型
int **p; // 去掉p,说明指针的类型是int **型
int p(int); // 去掉p,剩下int (int),是一个普通的函数
int (*p)(int); // 去掉p,说明指针的类型是int (*)(int)型
int *(*p(int))[3]; // 去掉p,说明指针的类型是int *(*(int))[3]型




int *p; // 去掉p和*,说明指针所指向的类型是int型
int *p[3]; // 因为[]的优先级高,所以p先和[3]结合,说明p是一个数组,再与*结合,说明这是一个指针数组,所以这里首先将p[3]去掉,然后再去掉*,剩下int,所以指针数组p[3]里面的元素所指向的内容为int型
int (*p)[3]; // 去掉p和*,说明指针所指向的类型是int [3]型,所以指针p指向的是大小为3的int型数组
int **p; // 去掉p和*,说明指针所指向的类型是int *型
int (*p)(int); // 去掉p和*,说明指针所指向的类型是int (int)型,所以指针p指向的是参数为int的函数,函数的返回类型为int型
int *(*p(int))[3]; // 因为()优先级高,p和(int)结合,说明p是一个函数,然后与*结合,说明函数的返回类型是一个指针,所以这里应该直接把(*p(int))去掉,剩下int *[3],所以函数p返回的是一个指向int *[3]型的指针

函数

  • 结构 back_type func_name(params){}

  • 变量考量:作用域,链接性,存储期

    • 计算机内存分区

      • 堆(malloc或new申请)

      • 栈(存储局部变量和函数调用信息。局部变量包括基本数据类型和指向其他数据结构的指针)

      • 全局(静态)存储区:用于存储全局变量和静态变量

      • 代码区:存放程序的二进制代码;在程序运行期间不会改变

    • 作用域:块,文件,静态变量作用域取决于声明位置

    • 存储期:自动(函数),静态(程序结束,例如全局变量),动态(堆中,new->delete或程序结束后消失)

    • 链接性:内部(全局变量+static),外部(全局变量),无(代码块+static)

    • static修饰作用:将变量放入全局存储区,并且限制在文件内部,外部文件无法访问或引用

      • 全局变量和用static修饰的静态全局变量区别在于外部是否可以访问

      • 一个文件声明了全局变量,另一个文件可以用extern来使用这个全局变量(但是不能赋值)extern int count;

      • extern 可用于函数,为默认形式;可以用extern "C" func(); 声明原型,表示采取C语言链接性

  • 函数指针

    • 函数名词即为函数的内存地址

    • 例如 double sum(int x) 该函数要作为参数传入其他函数,则为 double (*fp)(int)

    • 申明一个函数double *mm(double *,int); 如果在函数中定义一个该函数类型的变量pf则为

      • double *( *pf)(double *,int)=mm;

编译

头文件

  • 包含内容

    • 函数原型

    • #define或const定义的常量

    • 结构声明

    • 类声明

    • 模板声明

    • 内联函数

  • 在一个文件中,同一个头文件只能包含一次(因此使用之前的防护方案#ifndef:此方案仍包含了多次,但是会忽略此间内容)

编译选项(gcc,g++都可以使用)

  • 预处理,编译部分:

  • -E 预处理后停止,主要是对宏的处理 例如 gcc -E a1.c -o a1.i

  • -S 进行编译生成汇编代码 例如 gcc -S a1.i -o a1.s

  • -c 将汇编代码生成目标文件(机器码),不可执行,因为还没进行连接(把库代码,其他文件代码引入) 例如 gcc -c a1.s -o a1.o

  • 最后 gcc a1.o -o a1 进行连接生成可执行文件;当然也可以一步到位,gcc a1.c -o a1生成可执行代码

  • 多个文件进行编译连接: gcc a1.c a2.c a3.c -o aa

    • 注意:如果进行编译连接,多个文件只能有一个main函数;但是只是生成目标代码,则不必有main函数

  • -Wall:给出警告信息

  • 链接部分:

  • -Idirectory 向gcc的头文件搜索路径下添加新目录

  • -L libdir 向gcc的库文件搜索路径下添加新目录;如果使用了自定义目录,该链接信息会被包含在可执行文件中,默认为/usr/lib下

  • -l name 提示连接程序在创建可执行文件的时候包含指定的库文件

    • 链接静态库(libname.a)或动态库(libname.so)的库文件

  • ar指令

    • 常以.a,.lib(windows)结尾

    • ar rcs libx.a file1.c file2.c (或者rc?) --》生成静态库

  • -shared 动态链接库;默认情况下,gcc会进行动态链接库

    • 常以.so,.dll(windows)结尾->用于动态链接(-shared)

    • gcc -shared -fpic -o libx.so file1.c file2.c ---》生成动态库

    • 方式2:gcc -fpic -c file1.c -o file1.o 然后 gcc -shared file1.o fil2.o -o libx.so //so可以变成libx.dll

  • 生成可执行文件

    • -static 静态链接所有库,创建一个静态可执行文件。静态链接优先。

    • 多个动态库的时候,顺序从高层次到低层次

    • gcc main.c ./libmymath.so -I inc/

    • gcc main.c -lmymath -I inc/ //这种情况下动态库在系统路径下自动搜索 libmymath.so库

    • gcc main.c -lmymath -L/usr/lib/ -I inc/ //这种情况下动态库在系统路径下自动搜索 libmymath.so库

    • gcc main.c -Wl,-rpath=./lib -lmymath -I inc/ //指定运行时搜索库的路径

Flow和交互

IO和复用

Socket


评论