C-Makro-Reflection in Zig
(jstrieb.github.io)Abbildung von C-Makros in Zig
-
Zig
- Zig ist eine neue Programmiersprache mit Schwerpunkt auf Low-Level- und Systemprogrammierung und etabliert sich als Sprache, die C ersetzen kann
- Sie befindet sich zwar noch in Entwicklung, wird aber bereits in Projekten wie Bun und TigerBeetle eingesetzt
- Eine der beeindruckendsten Funktionen von Zig ist die hervorragende Interoperabilität mit C
-
Aufruf externer Bibliotheken
- In Zig lassen sich externe Bibliotheken einfach aufrufen
- Beispielcode:
const win = @import("std").os.windows; extern "user32" fn MessageBoxA(?win.HWND, [*:0]const u8, [*:0]const u8, u32,) callconv(win.WINAPI) i32; pub fn main() !void { _ = MessageBoxA(null, "world!", "Hello", 0); }
-
Import von C-Header-Dateien
- In Zig können C-Header-Dateien importiert und wie normale Zig-Imports verwendet werden
- Beispielcode:
const win32 = @cImport({ @cInclude("windows.h"); @cInclude("winuser.h"); }); pub fn main() !void { _ = win32.MessageBoxA(null, "world!", "Hello", 0); }
-
Windows-Programmierung
- Eine typische Windows-Anwendung besitzt eine
main-Funktion und eine Window-Procedure-Funktion - Die
main-Funktion initialisiert die Anwendung und führt eine Schleife aus, die Nachrichten an die Window-Procedure weiterleitet - Die Window-Procedure empfängt und verarbeitet diese Nachrichten
- Beispielcode:
const std = @import("std"); const windows = std.os.windows; const win32 = @cImport({ @cInclude("windows.h"); @cInclude("winuser.h"); }); var stdout: std.fs.File.Writer = undefined; pub export fn WindowProc(hwnd: win32.HWND, uMsg: c_uint, wParam: win32.WPARAM, lParam: win32.LPARAM) callconv(windows.WINAPI) win32.LRESULT { _ = switch (uMsg) { win32.WM_CLOSE => win32.DestroyWindow(hwnd), win32.WM_DESTROY => win32.PostQuitMessage(0), else => { stdout.print("Unknown window message: 0x{x:0>4}\n", .{uMsg}) catch undefined; }, }; return win32.DefWindowProcA(hwnd, uMsg, wParam, lParam); } pub export fn main(hInstance: win32.HINSTANCE) c_int { stdout = std.io.getStdOut().writer(); var class = std.mem.zeroes(win32.WNDCLASSEXA); class.cbSize = @sizeOf(win32.WNDCLASSEXA); class.style = win32.CS_VREDRAW | win32.CS_HREDRAW; class.hInstance = hInstance; class.lpszClassName = "Class"; class.lpfnWndProc = WindowProc; _ = win32.RegisterClassExA(&class); const hwnd = win32.CreateWindowExA(win32.WS_EX_CLIENTEDGE, "Class", "Window", win32.WS_OVERLAPPEDWINDOW, win32.CW_USEDEFAULT, win32.CW_USEDEFAULT, win32.CW_USEDEFAULT, win32.CW_USEDEFAULT, null, null, hInstance, null); _ = win32.ShowWindow(hwnd, win32.SW_NORMAL); _ = win32.UpdateWindow(hwnd); var message: win32.MSG = std.mem.zeroes(win32.MSG); while (win32.GetMessageA(&message, null, 0, 0) > 0) { _ = win32.TranslateMessage(&message); _ = win32.DispatchMessageA(&message); } return 0; }
- Eine typische Windows-Anwendung besitzt eine
-
Reflection
- Das Mapping von C-Makros kann umständlich sein
- In Zig lassen sich mit der Funktion
@typeInfoStrukturfelder und Deklarationen auflisten - Dadurch können C-Makros in Zig reflektiert werden
- Beispielcode:
const window_messages = get_window_messages(); fn get_window_messages() [65536][:0]const u8 { var result: [65536][:0]const u8 = undefined; @setEvalBranchQuota(1000000); for (@typeInfo(win32).Struct.decls) |field| { if (field.name.len >= 3 and std.mem.eql(u8, field.name[0..3], "WM_")) { const value = @field(win32, field.name); result[value] = field.name; } } return result; } pub export fn WindowProc(hwnd: win32.HWND, uMsg: c_uint, wParam: win32.WPARAM, lParam: win32.LPARAM) callconv(windows.WINAPI) win32.LRESULT { _ = switch (uMsg) { win32.WM_CLOSE => win32.DestroyWindow(hwnd), win32.WM_DESTROY => win32.PostQuitMessage(0), else => { stdout.print("{s}: 0x{x:0>4}\n", .{ window_messages[uMsg], uMsg }) catch undefined; }, }; return win32.DefWindowProcA(hwnd, uMsg, wParam, lParam); }
-
Fazit
- Zig kann die Funktionen von C komfortabler bereitstellen und nutzt dabei modernere Sprachkonstrukte
- Zig enthält eine C-Compiler-Toolchain und kann Deklarationen aus C-Header-Dateien nahtlos einbinden
- Zigs pragmatische Philosophie wird sofort deutlich, sobald man beginnt, die Sprache zu lernen
- Das intuitive und konsistente Design von Zig trägt zur höheren Produktivität bei
Zusammenfassung von GN⁺
- Zig ist eine neue Sprache mit Schwerpunkt auf Low-Level- und Systemprogrammierung und bietet hervorragende Interoperabilität mit C
- Zig kann C-Header-Dateien importieren und verwenden sowie C-Makros in Zig reflektieren
- Zigs pragmatische Philosophie und intuitives Design helfen stark beim Lernen und beim praktischen Einsatz der Sprache
- Zig bietet einen Weg, bestehende C-Codebasen nach Zig zu überführen, und senkt damit Hürden für die Einführung der Sprache
1 Kommentare
Hacker-News-Kommentar
Die Funktion
@cImportsoll entfernt werdenlibclangzu beseitigen, soll diese Funktion aus der Sprache entfernt werdenBeispielcode:
Entsprechender Code in D:
Der Compiler erledigt den Rest
Manche wünschen sich eine spezielle Syntax zum Importieren von C-Dateien, aber diese Einfachheit ist besser
Ich würde Zig gern mögen, habe aber mit einigen Problemen zu kämpfen
zig initzu starten, viel unnötigen Codezig build-exe filename.zigüberspringen kannDer Präprozessor von Clang ist nicht als separater Schritt vor der Kompilierung implementiert
Ich habe einen Blogbeitrag darüber geschrieben, wie man in D mit ImportC etwas Ähnliches machen kann
Es sieht so aus, als würde jedes Enum der Binärdatei mindestens
UINT16_MAX*sizeof(intptr_t)Byte hinzufügenDie Funktionsdefinitionen sehen sehr gut lesbar aus
Mir gefällt die Website