Ekosistem C memuat jutaan baris pustaka yang sudah teruji, dan Zig dirancang untuk dapat memakainya tanpa menulis pengikat (binding) manual. Alat utamanya adalah zig translate-c, sebuah penerjemah yang membaca kode C dan menghasilkan kode Zig yang setara. Topik ini mempraktikkan penerjemahan sebuah header, membaca bentuk hasilnya, dan memanggil fungsinya dari program Zig.
Konsep#
Perintah zig translate-c berkas.h mencetak kode Zig ke keluaran standar, dan hasilnya disimpan menjadi berkas .zig biasa yang di-import seperti modul lain. Seluruh deklarasi dari header, mulai dari struct, typedef, sampai fungsi static inline, hadir sebagai deklarasi publik pada berkas hasil. Penerjemah bekerja sepenuhnya pada waktu kompilasi, sehingga tidak ada pustaka penghubung tambahan untuk header yang murni berisi definisi.
Hasil penerjemahan terlihat sedikit asing pada pandangan pertama. Pointer C menjadi tipe [*c]T yang bisa bernilai null, fungsi C membawa callconv(.c) untuk menegaskan konvensi pemanggilannya, dan struktur berubah menjadi extern struct dengan tata letak yang dijamin sama. Bentuk-bentuk ini adalah representasi Zig yang jujur atas apa yang dinyatakan C, dan kode pemanggil tidak perlu menulis bentuk tersebut secara manual karena sudah tersedia dari hasil penerjemahan.
Nama deklarasi dipertahankan apa adanya, sehingga mencari fungsi di berkas hasil berarti mencari nama yang sama di header aslinya. Kegunaan itu menjadikan berkas hasil layak dibaca sekilas sebelum dipakai, sebab pembacaan singkat menyingkap deklarasi mana yang benar-benar diterjemahkan dan bentuk tipe yang dituntut pemanggilannya. Pustaka standar menyertakan pembantu penerjemahan pada std.zig.c_translation yang dipanggil berkas hasil untuk menutup celah makro dan builtin C, dan bagian itu tidak perlu ditulis manual oleh pemakai.
Alur kerjanya berurutan sebagai berikut.
- Simpan atau temukan header C yang hendak dipakai.
- Jalankan
zig translate-c header.h > header.ziguntuk menghasilkan berkas Zig. - Baca cuplikan hasilnya untuk mengenali nama-nama deklarasi.
- Import berkas hasil dari program Zig dan panggil deklarasinya.
Contoh Lengkap#
Header contoh mendefinisikan satu struktur Kotak beserta dua fungsi static inline untuk luas dan kelilingnya. Nama berkasnya header.h.
// tidak-dijalankan: berkas header C diterjemahkan lewat perintah zig translate-c
#ifndef KALKULATOR_H
#define KALKULATOR_H
typedef struct {
double sisi;
} Kotak;
static inline double luas_kotak(const Kotak *k) {
return k->sisi * k->sisi;
}
static inline double keliling_kotak(const Kotak *k) {
return 4.0 * k->sisi;
}
#endifPenerjemahan dijalankan dengan pengalihan keluaran agar hasilnya tersimpan, kemudian bagian penting dari header.zig diperiksa.
# tidak-dijalankan: penerjemahan pertama mengompilasi paket translate-c sehingga melampaui batas waktu sandbox
zig translate-c header.h > header.zigBerkas header.zig hasil penerjemahan disertakan pada direktori topik ini sehingga program pemakainya dapat dijalankan langsung. Berkas hasil memuat ratusan baris, tetapi sebagian besar berupa definisi makro lingkungan yang tidak dipakai. Penerjemah mencantumkan seluruh makro prapemroses yang dikenalnya, mulai dari __STDC__ sampai konstanta versi, karena makro C tidak memiliki padanan deklarasi Zig dan diterjemahkan menjadi konstanta comptime. Bagian yang dibutuhkan program pemakai selalu berada di bagian awal berkas, tepat setelah dua baris alias __builtin dan __helpers, sehingga pembacaan selektif cukup dilakukan dari atas. Cuplikan berikut memperlihatkan bagian yang relevan, disalin dari header.zig hasil penerjemahan di atas.
pub const Kotak = extern struct {
sisi: f64 = 0,
pub const luas_kotak = __root.luas_kotak;
pub const keliling_kotak = __root.keliling_kotak;
pub const kotak = __root.luas_kotak;
};
pub fn luas_kotak(arg_k: [*c]const Kotak) callconv(.c) f64 {
var k = arg_k;
_ = &k;
return k.*.sisi * k.*.sisi;
}
pub fn keliling_kotak(arg_k: [*c]const Kotak) callconv(.c) f64 {
var k = arg_k;
_ = &k;
return @as(f64, 4.0) * k.*.sisi;
}Struktur Kotak menjadi extern struct berisi f64, dan kedua fungsinya menjadi fungsi Zig biasa dengan parameter [*c]const Kotak. Program pemakainya melakukan import terhadap berkas hasil tersebut dan memanggil keduanya.
// tidak-dijalankan: berkas pemakai dieksekusi lewat blok bash karena mengimpor header.zig dari direktori topik
const std = @import("std");
const c = @import("header.zig");
pub fn main() void {
const kotak: c.Kotak = .{ .sisi = 2.5 };
std.debug.print("luas: {d:.2}\n", .{c.luas_kotak(&kotak)});
std.debug.print("keliling: {d:.2}\n", .{c.keliling_kotak(&kotak)});
}Pemanggilan c.luas_kotak(&kotak) mengirim penunjuk *const Kotak, dan Zig mengkonversikannya ke [*c]const Kotak secara otomatis. Jalankan programnya setelah langkah penerjemahan selesai.
zig run pakai-c.zigluas: 6.25
keliling: 10.00Angka 6.25 berasal dari 2.5 dikali 2.5, sedangkan 10.00 berasal dari 4.0 dikali 2.5, dan keduanya dihitung oleh kode C yang telah diterjemahkan ke Zig. Tidak ada file .c yang dikompilasi pada contoh ini karena kedua fungsinya static inline, sehingga seluruh implementasinya ikut tertulis pada berkas hasil penerjemahan.
Kesalahan umum#
Kesalahan kedua berupa berkas hasil yang basi. Header disunting tetapi header.zig tidak diterjemahkan ulang, sehingga program memakai deklarasi lama tanpa satu pun peringatan. Deklarasi baru tidak ditemukan dengan pesan seperti error: root source file struct has no member named ..., dan perbaikannya adalah menjalankan zig translate-c setiap kali header berubah, atau menambahkan langkah penerjemahan ke build.zig.
Kesalahan ketiga berupa berharap hasil penerjemahan berbentuk Zig idiomatik. Pointer [*c]T yang dapat bernilai null, variabel hasil terjemahan yang ditandai dengan _ = &k, dan callconv(.c) adalah bentuk sah hasil penerjemahan, bukan cacat yang wajib dirapikan. Lapisan pembungkus idiomatik ditulis sendiri di atas hasil penerjemahan bila diperlukan.
Ringkasan#
zig translate-cmenerjemahkan kode C menjadi berkas Zig yang di-import seperti modul biasa.- Struktur C menjadi
extern struct, pointer C menjadi[*c]T, dan fungsi C membawacallconv(.c). - Header yang berubah wajib diterjemahkan ulang agar berkas hasil tidak basi.
- Builtin
@cImportdari versi sebelumnya sudah tidak tersedia pada 0.17.0.
Referensi#
- C-Translation-CLI — Zig Language Reference
— Perintah
zig translate-cbeserta catatan pemakaiannya. - C-Pointers — Zig Language Reference
— Makna tipe
[*c]Thasil penerjemahan.