new和malloc的区别:

  1. new 一般用于C++, malloc一般用于C, 当然C++中也可以使用malloc,因为C++兼容C
  2. new 有类型, malloc无类型 void*
  3. new 会执行构造函数,然后再分配; malloc不会
  4. new 运算符, malloc 函数
    进程
    ps
    kill -9 强制信号,不忽略
    IPC

Unix三大版本

  • System V
  • Berkley
  • Hybrid -linux

封装 继承 多态

POSIX

GPL

GCC的作用:

1 预处理 2 编译 3 汇编 4 链接

gcc -E 只做预处理 生成main.i文件 gcc -E main.c -o main.i

gcc -c 编译 生成只编译不链接的main.o文件 gcc -c main.c

gcc -S 汇编 生成main.s文件汇编文件 gcc -S main.c

gcc 链接 gcc main.i / gcc main.o / gcc main.s 不指定名字 生成a.out

gcc -o 指定目标文件名

gcc -Wall 尽可能多的显示警告信息

gcc -Werror 将警告当作错误处理

gcc -v 显示版本号

gcc -I(注意:是i的大写,不是L的小写) 可以指定头文件所在的目录

Unix/Linux-01_ubuntu

#include <cstdio>
#define VERSION 2
#if (VERSION<3)
#error "版本太低"
#elif (VERSION>3)
#warning "版本太高"
#endif
int main()
{
printf("hello world!\n");
return 0;
}

警告 不影响a.out的生成与运行
错误 不会生成a.out

头文件

项目开发时,都会把各种声明和定义,全局变量放在头文件中,实现的代码放在.c文件中。

​#include ""可以先查找当前目录,而后系统目录​​​​#include <>只查找系统目录​

系统标准目录

​/usr/local/include​

​/usr/lib/gcc-lib/.../版本/include​

​/usr/include​

C++优先查找

​/usr/include/g++​

​#include <sys/time.h> 在所有系统标准目录下的找子目录 sys,并寻找time.h文件​

Unix/Linux-01_静态库_02

#include <cstdio>
int main()
{
printf("hello world!line:%d\n", __LINE__);
#line 15
printf("hello world!line:%d\n", __LINE__);
printf("hello world!line:%d\n", __LINE__);
return 0;
}

#line

C中 只是在该行之后改变了__LINE__的值
C++中 将跳过#line定义的n行数,从n+1行处开始运行
C++中 #line line_number “filename”

#pragma

Unix/Linux-01_Unix_03

// 如果main.c 比当前文件新,会产生警告
#pragma GCC dependency "main.c"
#pragma GCC poison goto add printf
int main()
{
goto ok;
printf("5 hello world!line:%d\n", __LINE__);
ok:printf("goto\n");
return 0;
}

​输出结果​

Unix/Linux-01_ubuntu_04

#pragma pack(1)

在结构体的对齐和补齐时,按照1的倍数(不再对齐和补齐)

#pragma pack(4) // 12 默认
#pragma pack(2) // 8
#pragma pack(1) // 6
struct s {
char c;
int i;
char ch;
};
printf("size: %d\n", sizeof(struct s));

预定义宏

_Pragma("OPT_LEVEL 2")

即:

#pragma OPT_LEVEL 2
_Pragma("GCC poison printf add")

编译环境变量

Unix/Linux-01_Unix_05

LD:指的是load
cd 回车

cd ~ 回车
一样都回到主目录
cd /
回到根目录

liujing@ubuntu:/$ cd
liujing@ubuntu:~$ pwd
/home/liujing
liujing@ubuntu:~$ ls -a
. .config .gnupg .profile .viminfo
.. c.txt .ICEauthority projects .vimrc
a.txt Desktop .java Public .vs
.bash_history .dmrc .keras .python_history .Xauthority
.bash_logout Documents .local server .xinputrc
.bashrc Downloads .mozilla snap .xsession-errors
b.txt examples.desktop Music .sudo_as_admin_successful .xsession-errors.old
.cache facenet .mysql_history Templates
.compiz .gconf Pictures Videos
liujing@ubuntu:~$ vi .bashrc
按G到最底部
添加
export PATH=$PATH:.
:wq 退出
liujing@ubuntu:~$ source .bashrc // 重新加载.bashrc

VIM的命令行模式

G 直接到最底部
gg 回到最顶部

头文件的查找方式

  1. 可以在""中指定路径查找
  2. 可以用gcc -I 指定头文件的查找目录
  3. 可以配置CPAHT或C_INCLUDE_PATH环境变量

写一个.h文件
写一个.c文件,如果内部函数没有被调用,则不引用头文件也可以被编译,但被使用时无法链接
gcc test.c add.c
./a.out
gcc test.c add.c -I ./add 指定头文件查找目录
或者
export CPATH=./add 配置环境变量, 暂时的, 重开终端后无效
想长期有效,要在.bashrc中配置,并source .bashrc

静态库和动态库

windows .lib / .dll
linux .a / .so
代码一般是以 库的形式打包。
库分为静态库和共享库。
静态库的代码在使用时需要复制完整的代码,而动态库的代码在使用时只保存一下代码的地址。
静态库不利用修改和维护,代码体积大,但好处是可以脱离静态库。(代码运行不需要静态库)
动态库修改和维护比较方便,代码体积小,但缺点是不能脱离动态库。(代码运行需要和动态库一起)

以后的开发,基本都是一个动态库文件+一个头文件。

源代码

// add.h ======================================
#ifndef ADD_H
#define ADD_H

int add(int, int);
double add2(double, double);

#endif

// add.c =======================================
int add(int a, int b){
return a + b;
}

double add2(double a, double b){
return a + b;
}

// test.c ======================================
#include <stdio.h>
#include "add.h"

int main()
{
printf("Hello world\n");

int i = add(1, 2);
double d= add2(1.0, 2.0);
printf("%d, %lf\n", i, d);
return 0;
}

静态库的步骤

生成库

  1. 写源代码 保存成 .c文件(add.c)
  2. 用 gcc 编译,生成 .o文件(gcc -c)
gcc -c acc.c // 只编译不链接时可没有头文件
  1. 用ar -r 命令生成 静态库文件
    ​​​ar -r libXX.a XXX.o​​​ (XX就是库文件名,XXX是目标文件-第二步生成的.o文件,有多少放多少)
    如果有多个.o文件
    ​​​ar -r libxx.a X1.o X2.o ... Xn.o​​ 注:使用库文件要提供.h文件
  2. ar -r libmy.a add.o

Unix/Linux-01_C_06

样例
liujing@ubuntu:~/projects/test/slib$ ls
add.c add.h test.c
liujing@ubuntu:~/projects/test/slib$ gcc -c add.c
liujing@ubuntu:~/projects/test/slib$ ls
add.c add.h add.o test.c
liujing@ubuntu:~/projects/test/slib$ ar -r libmy.a add.o
ar: creating libmy.a

使用库

  1. 写源代码,保存成 .c文件(test.c)
  2. 编译代码,生成 .o文件(gcc -c)
  3. 链接,有三种方式:
  1. 直接链接库文件 gcc test.o libXX.a 或者 gcc test.c libXX.a (不推荐)
 liujing@ubuntu:~/projects/test/slib$ gcc test.c
/tmp/ccxnH3Pi.o: In function `main':
test.c:(.text+0x1d): undefined reference to `add'
test.c:(.text+0x39): undefined reference to `add2'
collect2: error: ld returned 1 exit status
liujing@ubuntu:~/projects/test/slib$ gcc test.c libmy.a
liujing@ubuntu:~/projects/test/slib$ ls
add.c add.h a.out libmy.a test.c
liujing@ubuntu:~/projects/test/slib$ a.out
Hello world
3, 3.000000
  1. 先配 LIBRARY_PATH环境变量,在gcc链接
    export LIBRARY_PATH=.
    gcc test.o -l XX
    直接 gcc test.c 或者 gcc test.o 均可
    gcc test.c -lmy
    gcc test.c -l my // -lmy 与 -l my均可
liujing@ubuntu:~/projects/test/slib$ gcc test.c -l my
/usr/bin/ld: cannot find -lmy
collect2: error: ld returned 1 exit status
liujing@ubuntu:~/projects/test/slib$ ls
add.c add.h libmy.a test.c
liujing@ubuntu:~/projects/test/slib$ export LIBRARY_PATH=.
liujing@ubuntu:~/projects/test/slib$ gcc test.c
/tmp/ccVN1acW.o: In function `main':
test.c:(.text+0x1d): undefined reference to `add'
test.c:(.text+0x39): undefined reference to `add2'
collect2: error: ld returned 1 exit status
liujing@ubuntu:~/projects/test/slib$ gcc test.c -l my
liujing@ubuntu:~/projects/test/slib$ ls
add.c add.h a.out libmy.a test.c
liujing@ubuntu:~/projects/test/slib$ ./a.out
Hello world
3, 3.000000
  1. 用-l 和-L 选项直接链接
    gcc -test.o -l XX -L .
    (-l 指定库文件名,-L 指定库文件所在的路径)
// 两者均可
gcc test.c -l my -L .
gcc test.c -l my -L.

直接编译与静态编译

liujing@ubuntu:~/projects/test/slib$ cat hello.c
#include <stdio.h>

int main()
{
printf("Hello world\n");
return 0;
}

liujing@ubuntu:~/projects/test/slib$ gcc hello.c
liujing@ubuntu:~/projects/test/slib$ ls
add.c add.h a.out hello.c libmy.a test.c
liujing@ubuntu:~/projects/test/slib$ gcc -static hello.c -o b.out
liujing@ubuntu:~/projects/test/slib$ ls -al
...
-rwxrwxr-x 1 liujing liujing 8600 Aug 4 16:00 a.out
-rwxrwxr-x 1 liujing liujing 912720 Aug 4 16:00 b.out
...

我们可以看到上面 a.out 与 b.out 文件大小相差很大

共享库的步骤

生成库

  1. 写源代码 保存成 .c文件(add.c) gcc -c add.c
  2. 用gcc 编译,生成 .o文件(gcc -c)
    gcc -c -fpic add.c (-fpic可以省略)
  3. 生成共享库 gcc -shared XXX.o -o libXX.so

使用库

与静态库的使用方式基本一致
共享库在运行时,需要配置 LD_LIBRARY_PATH

export LD_LIBRARY_PATH=.

编写使用的源代码test.c

liujing@ubuntu:~/projects/test/lib$ gcc test.c -l add -L.
liujing@ubuntu:~/projects/test/lib$ ls
add.c add.h add.o a.out dl.c libadd.so test.c
liujing@ubuntu:~/projects/test/lib$ ./a.out
./a.out: error while loading shared libraries: libadd.so: cannot open shared object file: No such file or directory

liujing@ubuntu:~/projects/test/lib$ export LD_LIBRARY_PATH=.
liujing@ubuntu:~/projects/test/lib$ ./a.out
Hello world
3, 3.000000

/lib
/usr/lib

Unix/Linux-01_ubuntu_07

dlopen 打开一个共享库
dlsym 打开一个函数,得到其函数指针
dlclose 关闭这个共享库
dlerror 查询错误

作业

写两个函数,分别打印实心菱形和空心菱形,分别把函数做成静态库和共享库,调用之。
基础不好的同学可以先不打印空心菱形。