Reflection macro C trong Zig
(jstrieb.github.io)Phản chiếu macro C trong Zig
-
Zig
- Zig là một ngôn ngữ lập trình mới tập trung vào lập trình mức thấp và hệ thống, đang được định vị như một ngôn ngữ có thể thay thế C
- Dù hiện vẫn đang trong quá trình phát triển, Zig đã được sử dụng trong các dự án như Bun và TigerBeetle
- Một trong những tính năng ấn tượng nhất của Zig là khả năng tương tác xuất sắc với C
-
Gọi thư viện bên ngoài
- Trong Zig, có thể gọi thư viện bên ngoài một cách dễ dàng
- Mã ví dụ:
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 file header C
- Trong Zig, có thể import file header C và sử dụng nó giống như import Zig thông thường
- Mã ví dụ:
const win32 = @cImport({ @cInclude("windows.h"); @cInclude("winuser.h"); }); pub fn main() !void { _ = win32.MessageBoxA(null, "world!", "Hello", 0); }
-
Lập trình Windows
- Một ứng dụng Windows điển hình có hàm main và hàm window procedure
- Hàm main khởi tạo ứng dụng và chạy vòng lặp chuyển tiếp message tới window procedure
- Window procedure nhận và xử lý các message đó
- Mã ví dụ:
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; }
-
Phản chiếu
- Việc ánh xạ macro C có thể khá phiền phức
- Trong Zig, có thể dùng hàm @typeInfo để liệt kê các field và declaration của struct
- Nhờ đó có thể phản chiếu macro C trong Zig
- Mã ví dụ:
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); }
-
Kết luận
- Zig có thể thực hiện các khả năng của C một cách thuận tiện hơn bằng cách sử dụng cấu trúc ngôn ngữ lập trình hiện đại hơn
- Zig tích hợp toolchain trình biên dịch C, cho phép đưa các declaration trong file header C vào một cách liền mạch
- Triết lý thực dụng của Zig bộc lộ rất rõ ngay khi bắt đầu học ngôn ngữ này
- Thiết kế trực quan và nhất quán của Zig góp phần nâng cao năng suất
Tóm tắt của GN⁺
- Zig là một ngôn ngữ mới tập trung vào lập trình mức thấp và hệ thống, nổi bật với khả năng tương tác xuất sắc với C
- Zig có thể import file header C để sử dụng, đồng thời có thể phản chiếu các macro C trong Zig
- Triết lý thực dụng và thiết kế trực quan của Zig là trợ giúp lớn trong quá trình học và sử dụng ngôn ngữ
- Zig cung cấp một lộ trình chuyển đổi codebase C hiện có sang Zig, giúp vượt qua rào cản trong việc chấp nhận ngôn ngữ
1 bình luận
Ý kiến trên Hacker News
Tính năng
@cImportsắp bị loại bỏMã ví dụ:
Mã tương đương trong ngôn ngữ D:
Trình biên dịch xử lý phần còn lại
Có người muốn có cú pháp đặc biệt để import file C, nhưng sự đơn giản này tốt hơn
Tôi muốn thích Zig nhưng đang gặp một vài vấn đề
zig initcó khá nhiều mã không cần thiếtzig build-exe filename.zigBộ tiền xử lý của Clang không được triển khai như một bước riêng trước khi biên dịch
Tôi đã viết một bài blog về cách làm việc tương tự trong ngôn ngữ D bằng ImportC
Có vẻ như mỗi enum sẽ thêm ít nhất UINT16_MAX*sizeof(intptr_t) byte vào file thực thi
Định nghĩa hàm trông rất dễ đọc
Tôi thích trang web này