簡體   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