国庆前,接到工作安排,未来会维护一些新的代码,其中包括 C++ 项目,大概看了一下,核心内容分为两部分:

  • 调用第三方动态库dll,用以采集数据
  • 利用zeromq与其他服务程序做通信以传递数据

看了一下利用 zeromq 通信的代码部分,走的是 C 语言的库, C++ 本来就几乎完全兼容 C 语言,即 C 语言代码可以不加修改的用于 C++ 。接下来就先熟悉一下 C 语言头文件的机制。

1. 头文件

为自己的代码添加头文件,就有点像go与C#中接口一样,有约束的作用,也方便了调用

#include "zmq.h"

ZMQ_EXPORT void *zmq_socket (void *, int type);
ZMQ_EXPORT int zmq_close (void *s);
//omit other code...

2. 链接

C/C++ 会经历预处理-编译-汇编处理变成目标文件,目标文件中包括了机器语言指令,虽然目标文件包含机器语言指令,但它并不是一个完整的程序。因为任何一门发展至今的编程语言,都不再可能从0开始写代码,都会调用语言平台提供的代码库(运行时库、标准库),当然也可能是动态库或者静态库,这个我们以后再表。

当编译器生成目标文件时,它并不包括代码中使用到的任何运行时库的机器代码。链接器会将目标文件与必需的运行时库例程相结合。链接器完成,则会创建可执行文件。

比如标准输入输出:

#include <stdio.h>

3. 第三方库

除了运行时库,还有第三方库,就拿 zeromq 官方C语言代码为例:

#include <zmq.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>

int main (void)
{
    printf ("Connecting to hello world server…\n");
    void *context = zmq_ctx_new ();
    void *requester = zmq_socket (context, ZMQ_REQ);
    zmq_connect (requester, "tcp://localhost:5555");

    int request_nbr;
    for (request_nbr = 0; request_nbr != 10; request_nbr++) {
        char buffer [10];
        printf ("Sending Hello %d…\n", request_nbr);
        zmq_send (requester, "Hello", 5, 0);
        zmq_recv (requester, buffer, 10, 0);
        printf ("Received World %d\n", request_nbr);
    }
    zmq_close (requester);
    zmq_ctx_destroy (context);
    return 0;
}

尖括号只在系统默认目录或者尖括号内的路径查找,通常用于引用标准库中自带的头文件,这里 zeromq 能够使用尖括号 <zmq.h> ,是因为官方默认你会安装至默认目录下,实际上在mac的M1版,路径也有所不同,前面博文提到过这个问题:

brew install zmq
# /opt/homebrew/Cellar/zeromq

好了,如果是上面的代码,在mac下,代码是编译不通过的,因为找不到 zmq.h 头文件,这里有两种方法可以解决这种问题:

方法一:自己补充一个头文件

编译器首先在程序源文件所在目录查找,如果未找到,则去系统默认目录查找,通常用于引用用户自定义的头文件。这种情况如果是用 vscode 做开发,又想利用智能提示和转到定义等操作记得修改配置。

image-20211017233715198

这时,引用头文件时,就要使用双引号:

#include "zmq.h"

方法二:修改编译器加载头文件路径配置

如果开发环境是visual studio,工程—属性—c/c++—常规—附加包含目录:加上头文件存放的目录。

如果开发环境是mac,zeromq安装后,是自带头文件的,编译器是gcc,请修改gcc配置即可。

image-20211017234946568