Linux的相关学习

一、用 gcc 生成 .a 静态库和 .so 动态库

1 步:编辑生成例子程序 hello.h hello.c main.c
程序 1: hello.h
#ifndef HELLO_H 
#define HELLO_H 
void hello(const char *name); 
#endif //HELLO_H
程序 2: hello.c
#include <stdio.h> 
void hello(const char *name) 
{
   printf("Hello %s!\n", name); 
}
程序 3: main.c
#include "hello.h"
 int main()
 {
   hello("everyone");
   return 0; 
 }
2 步:将 hello.c 编译成 .o文件。
输入   gcc -c hello.c以得到hello.c文件
并用ls语法查询是否成功生成
3 步:由 .o 文件创建静态库
静态库文件命名规范:以lib作为前缀,是.a文件;
输入  ar -crv libmyhello.a hello.o 创建静态库文件。

4 步:在程序中使用静态库。

(1)先生成 main.o : 输入 gcc -c main.c
(2)再生成可执行文件: 再输入 gcc -o hello main.o libmyhello.a
(3)其次输入./hello 输出结果
成功输出!
(4)然后验证动态库的特点:
即在删掉静态库的情况下,运行可执行文件,发现程序仍旧正常运行,表明静态库跟程序执行没有联系。发现依旧成功输出,也表明静态库是在程序编译的时候被连接到代码中的。
5 步:由 .o 文件创建动态库文件。
(1)创建动态库
动态库文件名命名规范和静态库文件名命名规范类似,也是在动态库名增加前缀 lib ,但其
文件扩展名为 .so 。例如:我们将创建的动态库名为 myhello ,则动态库文件名就是 libmyh
ello.so 。用 gcc 来创建动态库。
输入  gcc -shared -fPIC -o libmyhello.so hello.o 来进行构建。
shared:表示指定生成动态链接库,不可省略
-fPIC:表示编译为位置独立的代码,不可省略
其中-o不可省略。

 (2)在程序中执行动态库

输入gcc -o hello main.c -L. -lmyhello或gcc main.c libmyhello.so -o hello 再运行可执行文件hello,


但是出现报错,这是因为程序在运行时, 会在/usr/lib /lib 等目录中查找需要的动态库文件。若找到,则载入动态库,否则将提 示类似上述错误而终止程序运行。我们将文件 libmyhello.so 复制到目录/usr/lib 中,再试试。

输入 mv libmyhello.so /usr/lib 可能因为需要权限,可以使用sudo指令,成功移动后用./hello成功输出。

至此,我们成功实践及学习了静态库与动态库。

二、GCC 编译器背后的故事

(一)、准备工作

由于 GCC 工具链主要是在 Linux 环境中进行使用,因此本文也将以 Linux 系统作为工作环境。为了能够演示编译的整个过程,先创建一个工作目录 test,然后用文本编辑器生成一个 C 语言编写的简单 Hello.c 程序为示例,其源代码如下所示:
#include <stdio.h> 
 int main(void) 
  { 
     printf("Hello World! \n"); 
     return 0; 
  }

(二)、 编译过程

1.预处理
预处理的过程主要包括以下过程:
(1) 将所有的#define 删除,并且展开所有的宏定义,并且处理所有的条件预编译指令,比如#if #ifdef #elif #else #endif 等。
(2) 处理#include 预编译指令,将被包含的文件插入到该预编译指令的位置。
(3) 删除所有注释“//”和“/* */”。
(4) 添加行号和文件标识,以便编译时产生调试用的行号及编译错误警告行号。
(5) 保留所有的#pragma 编译器指令,后续编译过程需要使用它们。
使用 gcc 进行预处理的命令为: gcc -E hello.c -o hello.i
hello.i 文件可以作为普通文本文件打开进行查看,其代码片段如下所示:
2.编译
编译过程就是对预处理完的文件进行一系列的词法分析,语法分析,语义分析及
优化后生成相应的汇编代码。
使用 gcc 进行编译的命令如下: gcc -S hello.i -o hello.s
上述命令生成的汇编程序 hello.s 的代码片段如下所示,其全部为汇编代码。 
3.汇编
汇编过程调用对汇编代码进行处理,生成处理器能识别的指令,保存在后缀为.o
的目标文件中。由于每一个汇编语句几乎都对应一条处理器指令,因此,汇编相
对于编译过程比较简单,通过调用 Binutils 中的汇编器 as 根据汇编指令和处理
器指令的对照表一一翻译即可。
当程序由多个源代码文件构成时,每个文件都要先完成汇编工作,生成.o 目标
文件后,才能进入下一步的链接工作。注意:目标文件已经是最终程序的某一部
分了,但是在链接之前还不能执行。
使用 gcc 进行汇编的命令如下: gcc -c hello.s -o hello.o
4.链接
链接也分为静态链接和动态链接,其要点如下:
(1) 静态链接是指在编译阶段直接把静态库加入到可执行文件中去,这样可执行文件会比较大。链接器将函数的代码从其所在地(不同的目标文件或静态链 接库中)拷贝到最终的可执行程序中。为创建可执行文件,链接器必须要完 成的主要任务是:符号解析(把目标文件中符号的定义和引用联系起来)和重定位(把符号定义和内存地址对应起来然后修改所有对符号的引用)。
(2) 动态链接则是指链接阶段仅仅只加入一些描述信息,而程序执行时再从系统中把相应动态库加载到内存中去。

(三)分析 ELF 文件

1、什么是ELF文件?

在计算机科学中,是一种用于二进制文件、可执行文件、目标代码、共享库和核心转储格式文件的文件格式。

是UNIX系统实验室(USL)作为应用程序二进制接口(Application Binary Interface,ABI)而开发和发布的,也是Linux的主要可执行文件格式。

2、ELF 文件的段

ELF 文件格式如下图所示,位于 ELF Header 和 Section Header Table 之间的都
是段(Section)。一个典型的 ELF 文件包含下面几个段:
.text:已编译程序的指令代码段。
.rodata:ro 代表 read only,即只读数据(譬如常数 const)。
.data:已初始化的 C 程序全局变量和静态局部变量。
.bss:未初始化的 C 程序全局变量和静态局部变量。
.debug:调试符号表,调试器用此段的信息帮助调试。、
3.反汇编 ELF
由于 ELF 文件无法被当做普通文本文件打开,如果希望直接查看一个 ELF 文件包
含的指令和数据,需要使用反汇编的方法。

三、Ubuntu下opencv操作学习

1.opencv的安装

参考:

(6条消息) Ubuntu18.04下OpenCV3.4.11的安装及使用示例_可乐有点好喝的博客-CSDN博客

(6条消息) Ubuntu18.04使用opencv库编写打开摄像头压缩视频_WOOZI9600L²的博客-CSDN博客

进行安装。

2、图片,视频的显示

(1)图片

创建一个文件夹存放代码文件:
touch code
cd code
创建一个 test1.cpp 文件。
nano test1.cpp
代码:

#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
	CvPoint center;
    double scale = -3; 

	IplImage* image = cvLoadImage("lena.jpg");
	argc == 2? cvLoadImage(argv[1]) : 0;
	
	cvShowImage("Image", image);
	
	
	if (!image) return -1; 	center = cvPoint(image->width / 2, image->height / 2);
	for (int i = 0;i<image->height;i++)
		for (int j = 0;j<image->width;j++) {
			double dx = (double)(j - center.x) / center.x;
			double dy = (double)(i - center.y) / center.y;
			double weight = exp((dx*dx + dy*dy)*scale);
			uchar* ptr = &CV_IMAGE_ELEM(image, uchar, i, j * 3);
			ptr[0] = cvRound(ptr[0] * weight);
			ptr[1] = cvRound(ptr[1] * weight);
			ptr[2] = cvRound(ptr[2] * weight);
		}

	Mat src;Mat dst;
	src = cvarrToMat(image);
	cv::imwrite("test.png", src);

    cvNamedWindow("test",1);  	imshow("test", src);
	 cvWaitKey();
	 return 0;
}

(2)视频

首先参考上面进行权限开放,进行连接

创建一个 test2.cpp 文件。
nano test2.cpp

代码为

#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
	//读取视频
	VideoCapture capture("MH.mp4");
	//循环显示每一帧
	while(1){
		Mat frame;//定义一个Mat变量,用于存储每一帧的图像
		capture >> frame;//读取当前帧
		if(frame.empty())//播放完毕,退出
			break;
		imshow("读取视频帧",frame);//显示当前帧
		waitKey(30);//掩饰30ms
	}
	system("pause");
	return 0;
}

代码讲解:

如果语句:VideoCapture capture(0),后面的参数设置为 0 ,则从摄像头读取视频并循环显示每一帧;如果设置为一个视频的文件名,比如:MH.mp4 ,则会将视频读取并循环显示每一帧。
while 循环体中的 Mat 数据结构其实是一个点阵,对应图像上的每一个点,点的集合形成了一帧图像,有关 Mat 详解请看:OpenCV中Mat数据结构
语句:waitKey(30) ,中的参数单位是 ms 毫秒,也就是每一帧间隔 30 ms ,该语句时不能删除的,否则会执行错误,无法播放视频或录制视频。
此代码会在while循环中一直运行,如果试图用鼠标关闭图像显示窗口,会发现始终关不掉。需要用键盘Ctrl+C 强制中断程序,非常不友好。
(原文链接:https://blog.csdn.net/weixin_46129506/article/details/120646081)

(3)开摄像头录视频

创建一个 test3.cpp 文件。
nano test3.cpp
代码:

/*********************************************************************
打开电脑摄像头,空格控制视频录制,ESC退出并保存视频RecordVideo.avi
*********************************************************************/
#include<iostream>
#include <opencv2/opencv.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;

int main()
{
	//打开电脑摄像头
	VideoCapture cap(0);
	if (!cap.isOpened())
	{
		cout << "error" << endl;
		waitKey(0);
		return 0;
	}

	//获得cap的分辨率
	int w = static_cast<int>(cap.get(CV_CAP_PROP_FRAME_WIDTH));
	int h = static_cast<int>(cap.get(CV_CAP_PROP_FRAME_HEIGHT));
	Size videoSize(w, h);
	VideoWriter writer("RecordVideo.avi", CV_FOURCC('M', 'J', 'P', 'G'), 25, videoSize);
	
	Mat frame;
	int key;//记录键盘按键
	char startOrStop = 1;//0  开始录制视频; 1 结束录制视频
	char flag = 0;//正在录制标志 0-不在录制; 1-正在录制

	while (1)
	{
		cap >> frame;
		key = waitKey(100);
		if (key == 32)//按下空格开始录制、暂停录制   可以来回切换
		{
			startOrStop = 1 - startOrStop;
			if (startOrStop == 0)
			{
				flag = 1;
			}
		}
		if (key == 27)//按下ESC退出整个程序,保存视频文件到磁盘
		{
			break;
		}

		if (startOrStop == 0 && flag==1)
		{
			writer << frame;
			cout << "recording" << endl;
		}
		else if (startOrStop == 1)
		{
			flag = 0;
			cout << "end recording" << endl;
			
		}
		imshow("picture", frame);
	}
	cap.release();
	writer.release();
	destroyAllWindows();
	return 0;
}

空格键开始,ESC键停止录制并保存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值