繁体   English   中英

如何在 Zig 中分配不完整类型的结构?

[英]How to allocate a struct of incomplete type in Zig?

我想在 Zig 中使用 POSIX 正则表达式例程,但我不知道如何分配模式缓冲区 ( regex_t )。 我认为问题在于它被定义为typedef struct re_pattern_buffer regex_t (在我的情况下,在 GNU 系统上),因此 Zig 无法判断它有多大。

在一个标准的zig init-exe项目(今天的 Zig master)中,我有以下main.zig

const std = @import("std");
const c = @cImport({@cInclude("regex.h");});

pub fn main() anyerror!void {
    var re: c.regex_t = undefined;
    std.log.info("address of re {}", .{re});
}

在其他默认的build.zig中,我添加了一行exe.linkLibC(); .

然后, zig build给出以下错误:

./src/main.zig:5:5: error: variable of type '.cimport:2:11.struct_re_pattern_buffer' not allowed
    var re: c.regex_t = undefined;
    ^

这很公平,但我无法弄清楚我应该做什么! 我可以看到一些潜在的解决方法:

  1. 直接使用struct re_pattern_buffer 但这不是可移植的,因为它不是 POSIX 标准的一部分(尽管至少 musl 和 glibc 将它用作regex_t的底层结构)。
  2. 编写一个malloc并返回regex_t的 C 函数,然后使用它。 应该没问题,因为所有 POSIX API 都采用regex_t * ,所以如果只需要处理指针,Zig 就不需要知道regex_t有多大。

但是,如果没有这些变通办法中的任何一种,那就太好了。 有什么提示吗?

struct_re_pattern_buffer被定义为opaque {}; 在 c 导入源中

// found by adding `--verbose-cimport` to the zig build
pub const struct_re_pattern_buffer = opaque {};
pub const regex_t = struct_re_pattern_buffer;

在 C 头文件中,它被定义为

struct re_pattern_buffer
{
  … // http://hte.sourceforge.net/doxygenized-0.8.0pre1/structre__pattern__buffer.html
};
typedef struct re_pattern_buffer regex_t;

它无法正确翻译结构的原因是 zig 尚未处理 cimported 结构中的位域( #1499 )。 它通常应该在 cimport 文件中显示错误,但由于某种原因这次不是:

pub const struct_re_dfa_t = opaque {}; // (no file):28:1: warning: struct demoted to opaque type - has bitfield

直接使用struct re_pattern_buffer; 但这不是可移植的,因为它不是 POSIX 标准的一部分(尽管至少 musl 和 glibc 将它用作 regex_t 的底层结构)。

这将不起作用,因为由于位域,zig 根本无法翻译结构。

编写一个 malloc 并返回 regex_t 的 C 函数,并使用它。 应该没问题,因为所有 POSIX API 都采用 regex_t *,所以 Zig 不需要知道 regex_t 有多大,如果它只需要处理指针。

这将起作用,并且通常是任何 cimport 问题的最简单的解决方法。

regex_t* alloc_regex_t(void);
void free_regex_t(regex_t* ptr);

如果您想使用 zig 分配器分配它,解决方法非常复杂:

要分配它,您需要知道它的大小。 你可以:

// header:
#include <stdint.h>
size_t my_sizeof_regex_t();
uint16_t my_alignof_regex_t();

// source:
#include <stdint.h>
#include <stdalign.h>
#include <regex.h>

size_t my_sizeof_regex_t() {
    return sizeof(regex_t);
}

uint16_t my_alignof_regex_t() {
    return alignof(regex_t);
}

在 zig 中,将其分配到指定了自定义对齐方式的字节数组中。

var re_zig_slice = try allocator.allocBytes(
    c.my_alignof_regex_t(),
    c.my_sizeof_regex_t(),
    0,
    @returnAddress(),
);
var re = @ptrCast(*c.regex_t, re_zig_slice.ptr);
defer try allocator.rawFree(@ptrCast([*]u8, re)[0..c.my_sizeof_regex_t()]), c.my_alignof_regex_t, @returnAddress());

这变得更加复杂,因为在 zig 中,分配器在分配和释放时需要知道对象的大小和对齐方式。 C 的 malloc 在内部存储大小以便正确释放,并且始终对它分配的所有内容使用单个对齐值。

注意:或者,如果您使用 c abi 中结构的最大对齐方式进行对齐,并且在释放它之前使用@alignCast指针 @alignCast ,则可以使用普通allocWithOptionsfree方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM