前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >通过RealSense代码说明一些C语言问题

通过RealSense代码说明一些C语言问题

作者头像
云深无际
发布2023-05-24 13:41:32
5040
发布2023-05-24 13:41:32
举报
文章被收录于专栏:云深之无迹云深之无迹

以前也读了这个RGBD相机的一些源码但是发现自己的基本功是一点也不好,所以就搁置了很久,今天试图来回答一些问题。

说好的不会再出新品结果还是出了,估计这个市场还是可以的

自己就看一个例子里面的代码

就一个C文件,看的也简单一些

代码语言:javascript
复制
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)

add_executable(rs-color rs-color.c ../example.h)
include_directories(../../common ../../third-party/imgui ../../C)
target_link_libraries(rs-color ${DEPENDENCIES})
set_target_properties (rs-color PROPERTIES
FOLDER "Examples/C"
)

install(TARGETS rs-color RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})

编译的文件都是使用Cmake来控制的,所以一开始写一些这个。

set(CMAKE_EXPORT_COMPILE_COMMANDS 1) 这个命令会让CMake在编译过程中输出 JSON 格式的编译命令到 compile_commands.json 文件中。这对于IDE的代码补全和静态分析很有帮助。

add_executable(rs-color rs-color.c ../example.h) 这个命令定义了一个rs-color的可执行目标,源代码文件是rs-color.c和example.h。

include_directories(../../common ../../third-party/imgui ../../C) 这个命令指定了包含路径,用于解析rs-color.c和example.h中的#include语句。

target_link_libraries(rs-color {DEPENDENCIES}) 这个命令为rs-color目标指定了链接库,其中{DEPENDENCIES}是一个变量,包含所有依赖库的名字。

set_target_properties (rs-color PROPERTIES FOLDER "Examples/C" )这个命令为rs-color目标设置了一些属性,这里指定了在IDE的项目视图中,rs-color会出现在Examples/C文件夹下。

直接下来就看几个代码,是不是和学的C语言不太一样

这条语句rs2_error *e = 0;

1. 定义了一个指针e,指向rs2_error类型。

2. 将e初始化为0,也就是RS2_ERROR_NONE,表示没有错误。

代码语言:javascript
复制
rs2_context *ctx = rs2_create_context(RS2_API_VERSION, &e);

源码使用 Intel RealSense SDK 的 C API 创建了一个上下文对象 rs2_context,并将其地址赋给 ctx 变量。

同时,它传递了 RealSense SDK 的 API 版本号 RS2_API_VERSIONrs2_create_context() 函数,该函数将返回一个 rs2_context 对象。

在创建上下文对象时,还传递了一个错误处理器(error-handler)的地址 &e,以便在运行时捕获可能出现的错误。

如果发生someError,会通过*e = ...将e设置为相应的错误码。之后,在调用者可以检查*e的值来查看doSomething()是否发生错误。这是C语言中一个很常见的错误处理方式 - 通过指针传递错误码,如果有错误,被调用的函数会设置该指针为错误值。

调用者在调用后检查该值来进行错误处理。这种方式的好处是:

  1. 可以从函数返回额外的错误信息(除了函数返回值本身)。
  2. 不需要定义专门的错误返回类型,可以直接使用指向已有类型的指针。
  3. 简单和实用,适用于C语言的语法和习惯。 当然,这个方式也有一定的缺点,比如: 1. 如果不注意检查错误指针,难以发现错误,这会影响健壮性。 2. 错误指针需要与函数的正确返回值区分开来检查,有一定难度。 3. 错误信息只能通过指定的指针值返回,表达能力较有限。所以,对于rs2_error *e这样的指针,是可以直接作为C函数的参数进行传递的,这是C语言中一种简单实用的错误处理方式,但是也有一定的缺陷。

在这里被定义了很多

更具体的实现

1.析构函数~rs2_context(),在rs2_context被释放时会调用ctx->stop()。这是用于停止某个线程或后台服务。

2. 一个std::shared_ptr成员ctx。这是一个librealsense库中的context对象,通过shared_ptr智能指针进行管理。可以猜测,这个rs2_context结构体表示一个与librealsense的context相关的对象,它在释放时会停止该context,并通过shared_ptr管理context的生命周期。其实这也是一个使用RAII(Resource Acquisition Is Initialization),通过在对象构造和析构时启动和停止资源,实现资源的自动管理。

代码语言:javascript
复制
  rs2_context *ctx = rs2_create_context(RS2_API_VERSION, &e);

这段代码中,通过调用rs2_create_context()函数创建了一个rs2_context 实例,并将该实例的指针赋值给了 ctx 变量。这个 rs2_context 实例是在 rs2_create_context() 函数内部创建并初始化的,然后将其地址返回给调用者,调用者通过 ctx 变量来访问和操作该实例。

可以说rs2_context实例已经被初始化并设置好了,但不能直接说 rs2_context 里面是一个已经初始化过的结构体,因为 rs2_context 只是一个指针类型,并不存储任何数据。

结构体指针在 C 语言中被广泛使用,因为它可以方便地访问和操作结构体中的成员,而不需要对整个结构体进行复制。结构体指针可以通过指针运算和取值运算符来访问结构体成员,这使得对结构体的操作变得更加高效。

以下是一些常见的使用结构体指针的场景:

  1. 传递结构体指针作为函数参数:这种情况下,函数可以通过指针来访问和修改结构体的成员,从而避免了对整个结构体进行复制,提高了程序的效率。
  2. 动态内存分配:当需要动态创建一个结构体对象时,需要使用结构体指针来指向该对象。在动态分配内存时,使用结构体指针可以确保只分配所需的内存,并且可以方便地释放分配的内存。
  3. 链表和树等数据结构:链表和树等数据结构通常使用结构体指针来连接不同的节点,从而构建出完整的数据结构。
代码语言:javascript
复制
 rs2_context *rs2_create_context(int api_version, rs2_error **error);

- api_version参数指定了librealsense API的版本号,用于向后兼容。 -e是个指针,如果有错误发生,会被设置为错误码。这是C语言常见的错误返回方式。

包含了以下字段:

  1. message:错误消息,描述错误 details 的字符串。
  2. function:发生错误的函数名。
  3. args:发生错误的函数调用的参数。
  4. exception_type:错误类型,很可能是一个enum,表示出错的原因。这个结构体通常用来表示异常信息,或是库函数调用后的错误详情。
代码语言:javascript
复制
c++
struct rs2_error 
{
    std::string message;   // 错误消息
    std::string function;  // 函数名
    std::string args;     // 函数参数
    rs2_exception_type exception_type; // 错误类型
};

如果一个函数返回一个结构体类型的值,那么需要使用一个结构体类型的变量来接收这个返回值。因为结构体类型通常比较大,如果直接将结构体类型的值作为函数的返回值返回,会导致复制整个结构体的内存空间,从而影响程序的性能。因此,C 语言中通常使用指向结构体的指针作为返回值,而不是直接返回结构体类型的值。

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>

struct person {
    char name[50];
    int age;
};

struct person* create_person(const char* name, int age) {
    struct person* p = (struct person*) malloc(sizeof(struct person));
    if (p != NULL) {
        strcpy(p->name, name);
        p->age = age;
    }
    return p;
}

int main() {
    struct person* p = create_person("John Doe", 30);
    if (p != NULL) {
        printf("Name: %s\n", p->name);
        printf("Age: %d\n", p->age);
        free(p);
    }
    return 0;
}

完整代码

看这个

在上面的例子中,create_person() 函数返回一个指向:

代码语言:javascript
复制
 struct person

结构体的指针。

该函数使用malloc()函数动态分配内存来存储结构体,然后将结构体的成员赋值为传入的参数。最后,该函数返回指向该结构体的指针。在 main() 函数中,调用 create_person() 函数来创建一个结构体实例,并打印出其成员的值。在使用完结构体后,还需要调用 free() 函数来释放动态分配的内存。

更具体的来分析:

代码语言:javascript
复制
    struct person* p = (struct person*) malloc(sizeof(struct person));
  1. 调用malloc()函数,请求分配sizeof(struct person)字节的内存块。这将分配足够存放person结构体的内存。
  2. malloc()返回 void *,所以我们需要强制类型转换为struct person*。这会将void *转换为person结构体的指针。
  3. person *p将保存分配的内存块地址,我们可以通过p访问这个person对象。
  4. 分配的内存未初始化,需要手工初始化 person 对象的各个字段。

使用malloc()获取内存,强制类型转换为需要的指针类型,使用后释放内存。

代码语言:javascript
复制
https://www.intelrealsense.com/
代码语言:javascript
复制
https://github.com/IntelRealSense/librealsens
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-04-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云深之无迹 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档