在 Zig 0.7.0 中访问 C 函数返回值的结构
Access Structs Returned by Value from C Functions in Zig 0.7.0
这是我在 Zig 0.7.0 中通过 linux-x86_64 上的@cImport 导入 Zig 的一些 C 代码。当我在 Zig 中直接创建一个 struct Point
结构时,它按预期工作,但是当我 return 一个来自 getPoint
方法的值有错误数据时(见下面的“输出”)。我做错了什么,还是这是一个错误?
- point.h
struct Point {
int x;
int y;
int z;
};
struct Point getPoint(void);
- point.c
#include "point.h"
#include <stdio.h>
struct Point getPoint() {
struct Point retVal = { .x=50, .y=50, .z=50 };
return retVal;
}
- main.zig
const std = @import("std");
const c = @cImport({
@cInclude("point.h");
});
pub fn main() void {
var point = c.getPoint();
var anotherPoint = c.Point{ .x = 50, .y = 50, .z = 50 };
std.debug.print("point x: {} y: {} z: {}\n", .{ point.x, point.y, point.z });
std.debug.print("anotherPoint x: {} y: {} z: {}\n", .{ anotherPoint.x, anotherPoint.y, anotherPoint.z });
}
- 输出
point x: 50 y: 50 z: -1705967616
anotherPoint x: 50 y: 50 z: 50
- build.zig
const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
//const lib = b.addStaticLibrary("interface", "src/libinterface.a");
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("point_test", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.linkLibC();
exe.addIncludeDir("src");
exe.install();
exe.addCSourceFile("src/point.c", &[_][]const u8{
"-Wall",
"-Wextra",
"-Werror",
});
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}
Zig 的 c abi 兼容性目前在结构和浮点数方面存在一些问题。
您遇到的具体问题 #3211 已得到修复,您的代码现在可以正常工作了。
$> zig run main.zig point.c -I.
point x: 50 y: 50 z: 50
anotherPoint x: 50 y: 50 z: 50
但是,C abi 互操作仍然存在问题,例如:#9487
在所有这些问题都得到解决之前,通常可以通过使用指针而不是按值传递参数和 return 值
来解决这个问题
// workaround.h
#include "point.h"
void workaround_getPoint(struct Point* out);
// workaround.c
#include "workaround.h"
void workaround_getPoint(struct Point* out) {
*out = getPoint();
}
// .zig
const c = @cImport({
@cInclude("point.h");
@cInclude("workaround.h");
});
pub fn getPoint(): c.Point {
var res: c.Point = undefined;
c.workaround_getPoint(&res);
return res;
}
// build.zig
exe.addCSourceFile("src/workaround.c", &.{ "-Wall", "-Wextra", "-Werror" });
这是我在 Zig 0.7.0 中通过 linux-x86_64 上的@cImport 导入 Zig 的一些 C 代码。当我在 Zig 中直接创建一个 struct Point
结构时,它按预期工作,但是当我 return 一个来自 getPoint
方法的值有错误数据时(见下面的“输出”)。我做错了什么,还是这是一个错误?
- point.h
struct Point {
int x;
int y;
int z;
};
struct Point getPoint(void);
- point.c
#include "point.h"
#include <stdio.h>
struct Point getPoint() {
struct Point retVal = { .x=50, .y=50, .z=50 };
return retVal;
}
- main.zig
const std = @import("std");
const c = @cImport({
@cInclude("point.h");
});
pub fn main() void {
var point = c.getPoint();
var anotherPoint = c.Point{ .x = 50, .y = 50, .z = 50 };
std.debug.print("point x: {} y: {} z: {}\n", .{ point.x, point.y, point.z });
std.debug.print("anotherPoint x: {} y: {} z: {}\n", .{ anotherPoint.x, anotherPoint.y, anotherPoint.z });
}
- 输出
point x: 50 y: 50 z: -1705967616
anotherPoint x: 50 y: 50 z: 50
- build.zig
const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
//const lib = b.addStaticLibrary("interface", "src/libinterface.a");
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("point_test", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.linkLibC();
exe.addIncludeDir("src");
exe.install();
exe.addCSourceFile("src/point.c", &[_][]const u8{
"-Wall",
"-Wextra",
"-Werror",
});
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}
Zig 的 c abi 兼容性目前在结构和浮点数方面存在一些问题。
您遇到的具体问题 #3211 已得到修复,您的代码现在可以正常工作了。
$> zig run main.zig point.c -I.
point x: 50 y: 50 z: 50
anotherPoint x: 50 y: 50 z: 50
但是,C abi 互操作仍然存在问题,例如:#9487
在所有这些问题都得到解决之前,通常可以通过使用指针而不是按值传递参数和 return 值
来解决这个问题// workaround.h
#include "point.h"
void workaround_getPoint(struct Point* out);
// workaround.c
#include "workaround.h"
void workaround_getPoint(struct Point* out) {
*out = getPoint();
}
// .zig
const c = @cImport({
@cInclude("point.h");
@cInclude("workaround.h");
});
pub fn getPoint(): c.Point {
var res: c.Point = undefined;
c.workaround_getPoint(&res);
return res;
}
// build.zig
exe.addCSourceFile("src/workaround.c", &.{ "-Wall", "-Wextra", "-Werror" });