If the goal is to be as simple as possible, I suggest you can even have no C header file. pgcd.c:
unsigned int
pgcd(unsigned int l, unsigned int r)
{
while (l != r) {
if (l > r) {
l = l - r;
} else {
r = r - l;
}
}
return l;
}
Now, use-pgcd.zig:
const std = @import("std");
const c = @cImport(@cInclude("pgcd.c")); // No need to have a .h
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
if (args.len != 3) {
std.debug.print("Usage: find-pgcd L R\n", .{});
return error.WrongArgs;
}
var l = try std.fmt.parseInt(u32, args[1], 10);
var r = try std.fmt.parseInt(u32, args[2], 10);
// A good reading is https://renato.athaydes.com/posts/testing-building-c-with-zig.html
std.debug.print("PGCD({d},{d}) = {d}\n", .{ l, r, c.pgcd(l, r) });
}
const expect = @import("std").testing.expect;
fn expectidentical(i: u32) !void {
try expect(c.pgcd(i, i) == i);
}
test "identical" {
try expectidentical(1);
try expectidentical(7);
try expectidentical(18);
}
test "primes" {
try expect(c.pgcd(4, 13) == 1);
}
test "pgcdexists" {
try expect(c.pgcd(15, 35) == 5);
}
test "pgcdlower" {
try expect(c.pgcd(15, 5) == 5);
}
And compile with:
% zig build-exe use-pgcd.zig -lc -I.
% ./use-pgcd 36 8
PGCD(36,8) = 4
Or if you prefer a build.zig:
const std = @import("std");
pub fn build(b: *std.Build) void {
const exe = b.addExecutable(.{
.name = "find-pgcd",
.root_source_file = .{ .path = "use-pgcd.zig" },
});
exe.addIncludePath(.{ .path = "." });
b.installArtifact(exe);
const lib = b.addStaticLibrary(.{
.name = "pgcd",
.root_source_file = .{ .path = "pgcd.c" },
.target = .{},
.optimize = std.builtin.OptimizeMode.Debug,
});
exe.linkLibrary(lib);
}