1 पॉइंट द्वारा GN⁺ 2024-07-31 | 1 टिप्पणियां | WhatsApp पर शेयर करें

Zig का C मैक्रो रिफ्लेक्शन

  • Zig

    • Zig एक नई programming language है जो low-level और system programming पर केंद्रित है, और C के विकल्प के रूप में अपनी जगह बना रही है
    • यह अभी development में है, लेकिन Bun और TigerBeetle जैसे projects में पहले से इस्तेमाल हो रही है
    • Zig की सबसे प्रभावशाली विशेषताओं में से एक C के साथ इसकी बेहतरीन interoperability है
  • बाहरी लाइब्रेरी कॉल करना

    • Zig में external libraries को आसानी से कॉल किया जा सकता है
    • उदाहरण कोड:
      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);
      }
      
  • C header files import करना

    • Zig में C header files को import करके सामान्य Zig import की तरह इस्तेमाल किया जा सकता है
    • उदाहरण कोड:
      const win32 = @cImport({
        @cInclude("windows.h");
        @cInclude("winuser.h");
      });
      pub fn main() !void {
        _ = win32.MessageBoxA(null, "world!", "Hello", 0);
      }
      
  • Windows programming

    • एक सामान्य Windows application में main function और window procedure function होता है
    • main function application को initialize करता है और messages को window procedure तक पहुंचाने वाला loop चलाता है
    • window procedure messages प्राप्त करके उन्हें process करता है
    • उदाहरण कोड:
      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;
      }
      
  • रिफ्लेक्शन

    • C macros को map करना झंझटभरा हो सकता है
    • Zig में @typeInfo function का उपयोग करके struct fields और declarations को सूचीबद्ध किया जा सकता है
    • इसके जरिए C macros को Zig में reflect किया जा सकता है
    • उदाहरण कोड:
      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);
      }
      
  • निष्कर्ष

    • Zig, C की क्षमताओं को अधिक आधुनिक programming language structure के साथ अधिक सुविधाजनक तरीके से उपलब्ध कराता है
    • Zig, C compiler toolchain को शामिल करते हुए C header files की declarations को सहज रूप से शामिल कर सकता है
    • Zig का pragmatism-केंद्रित दर्शन भाषा सीखना शुरू करते ही स्पष्ट दिखाई देता है
    • Zig का intuitive और consistent design productivity बढ़ाने में मदद करता है

GN⁺ का सारांश

  • Zig low-level और system programming पर केंद्रित एक नई भाषा है, जो C के साथ बेहतरीन interoperability प्रदान करती है
  • Zig, C header files को import करके इस्तेमाल कर सकता है, और C macros को Zig में reflect भी कर सकता है
  • Zig का pragmatism-केंद्रित दर्शन और intuitive design भाषा को सीखने और इस्तेमाल करने में बड़ी मदद करते हैं
  • Zig, मौजूदा C codebase को Zig में लाने का रास्ता देता है, जिससे language adoption की बाधाएँ कम होती हैं

1 टिप्पणियां

 
GN⁺ 2024-07-31
Hacker News राय
  • @cImport फीचर को हटाए जाने की योजना है

    • C फ़ाइलें import करना संभव है, लेकिन इसके लिए अधिक काम करना पड़ता है
    • libclang dependency हटाने के लिए इस फीचर को भाषा से निकालने की कोशिश की जा रही है
  • उदाहरण कोड:

    const win32 = @cImport({
      @cInclude("windows.h");
      @cInclude("winuser.h");
    });
    
    pub fn main() !void {
      _ = win32.MessageBoxA(null, "world!", "Hello", 0);
    }
    
  • D भाषा में समकक्ष कोड:

    import windows, winuser;
    void main() {
      MessageBoxA(null, "world!", "Hello", 0);
    }
    
  • compiler बाकी सब संभाल लेता है

  • कुछ लोग C फ़ाइलें import करने के लिए विशेष syntax की मांग कर रहे हैं, लेकिन यह सादगी बेहतर है

  • मैं Zig को पसंद करना चाहता हूँ, लेकिन कुछ समस्याओं का सामना कर रहा हूँ

    • मेरा मानना है कि इनमें से अधिकतर इसलिए हैं क्योंकि यह अभी 1.0 version नहीं है
    • उदाहरण के लिए, zig init से project शुरू करने का सुझाया गया तरीका बहुत सारा अनावश्यक code जोड़ देता है
    • हाल ही में पता चला कि zig build-exe filename.zig से initialization वाला हिस्सा छोड़ा जा सकता है
    • editor integration की समस्याएँ भी काफ़ी थीं
    • मैंने VSCode extension install किया, लेकिन auto-complete वगैरह ठीक से काम नहीं कर रहे हैं
    • शायद यह user error हो; सप्ताहांत में फिर से कोशिश करूँगा
  • Clang का preprocessor अलग compile से पहले के चरण के रूप में implement नहीं किया गया है

    • मूल रूप से यह lexer का हिस्सा है
    • मुझे लगता है gcc भी इसी तरह का तरीका इस्तेमाल करता होगा
    • macro names तक पहुँचना तकनीकी रूप से असंभव नहीं है
    • इसकी ज़्यादा मांग नहीं है, इसलिए इसे implement नहीं किया गया
  • D भाषा में ImportC का उपयोग करके ऐसा ही काम कैसे किया जा सकता है, इस पर एक blog लिखा गया है

  • ऐसा लगता है कि हर enum executable में कम से कम UINT16_MAX*sizeof(intptr_t) bytes जोड़ देगा

  • function definitions काफ़ी पढ़ने में आसान लगती हैं

    • मैंने इसे दूसरी भाषाओं में भी देखा है, लेकिन आमतौर पर वह बहुत भयानक होता है
    • शायद Zig सीखना worthwhile हो सकता है
    • यह एक killer feature है
  • साइट पसंद आई

    • लगता है Zig सचमुच लोकप्रिय हो रहा है