# Zig에서의 C 매크로 리플렉션

> Clean Markdown view of GeekNews topic #16101. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=16101](https://news.hada.io/topic?id=16101)
- GeekNews Markdown: [https://news.hada.io/topic/16101.md](https://news.hada.io/topic/16101.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2024-07-31T09:54:29+09:00
- Updated: 2024-07-31T09:54:29+09:00
- Original source: [jstrieb.github.io](https://jstrieb.github.io/posts/c-reflection-zig/)
- Points: 1
- Comments: 1

## Topic Body

### Zig의 C 매크로 반영

- **Zig**
  - Zig는 저수준 및 시스템 프로그래밍에 중점을 둔 새로운 프로그래밍 언어로, C를 대체할 수 있는 언어로 자리 잡고 있음
  - 현재 개발 중이지만, 이미 Bun과 TigerBeetle 같은 프로젝트에서 사용되고 있음
  - Zig의 가장 인상적인 기능 중 하나는 C와의 뛰어난 상호 운용성임

- **외부 라이브러리 호출**
  - Zig에서는 외부 라이브러리를 쉽게 호출할 수 있음
  - 예시 코드:
    ```zig
    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 헤더 파일 가져오기**
  - Zig에서는 C 헤더 파일을 가져와서 일반 Zig 가져오기처럼 사용할 수 있음
  - 예시 코드:
    ```zig
    const win32 = @cImport({
      @cInclude("windows.h");
      @cInclude("winuser.h");
    });
    pub fn main() !void {
      _ = win32.MessageBoxA(null, "world!", "Hello", 0);
    }
    ```

- **윈도우 프로그래밍**
  - 일반적인 윈도우 애플리케이션은 main 함수와 window procedure 함수를 가짐
  - main 함수는 애플리케이션을 초기화하고 메시지를 window procedure로 전달하는 루프를 실행함
  - window procedure는 메시지를 받아 처리함
  - 예시 코드:
    ```zig
    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 매크로를 매핑하는 것은 번거로울 수 있음
  - Zig에서는 @typeInfo 함수를 사용하여 구조체 필드와 선언을 나열할 수 있음
  - 이를 통해 C 매크로를 Zig에서 반영할 수 있음
  - 예시 코드:
    ```zig
    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의 기능을 더 현대적인 프로그래밍 언어 구조를 사용하여 더 편리하게 수행할 수 있음
  - Zig는 C 컴파일러 도구 체인을 포함하여 C 헤더 파일의 선언을 원활하게 포함할 수 있음
  - Zig의 실용주의 철학은 언어를 배우기 시작하면 바로 드러남
  - Zig의 직관적이고 일관된 설계는 생산성을 높이는 데 기여함

### GN⁺의 정리
- Zig는 저수준 및 시스템 프로그래밍에 중점을 둔 새로운 언어로, C와의 뛰어난 상호 운용성을 자랑함
- Zig는 C 헤더 파일을 가져와서 사용할 수 있으며, C 매크로를 Zig에서 반영할 수 있음
- Zig의 실용주의 철학과 직관적인 설계는 언어를 배우고 사용하는 데 큰 도움이 됨
- Zig는 기존 C 코드베이스를 Zig로 전환할 수 있는 경로를 제공하여 언어 채택의 장애물을 극복함

## Comments



### Comment 27707

- Author: neo
- Created: 2024-07-31T09:54:29+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=41106686) 
- @cImport 기능이 제거될 예정임
  - C 파일을 가져오는 것은 가능하지만 더 많은 작업이 필요함
  - libclang 의존성을 제거하기 위해 이 기능을 언어에서 제거하려고 함

- 예제 코드:
  ```zig
  const win32 = @cImport({
    @cInclude("windows.h");
    @cInclude("winuser.h");
  });

  pub fn main() !void {
    _ = win32.MessageBoxA(null, "world!", "Hello", 0);
  }
  ```

- D 언어의 동등한 코드:
  ```d
  import windows, winuser;
  void main() {
    MessageBoxA(null, "world!", "Hello", 0);
  }
  ```

- 컴파일러가 나머지를 처리함
- C 파일을 가져오는 특별한 구문을 요청하는 사람들이 있지만, 이 간단함이 더 좋음

- Zig를 좋아하고 싶지만 몇 가지 문제를 겪고 있음
  - 대부분은 아직 1.0 버전이 아니기 때문이라고 생각함
  - 예를 들어, `zig init`으로 프로젝트를 시작하는 권장 방법은 불필요한 코드가 많음
  - 최근에 `zig build-exe filename.zig`로 초기화 부분을 건너뛸 수 있다는 것을 알게 됨
  - 에디터 통합 문제도 많았음
  - VSCode 확장을 설치했지만 자동 완성 등이 제대로 작동하지 않음
  - 아마도 사용자 오류일 가능성이 높아 주말에 다시 시도해볼 예정임

- Clang의 전처리기는 별도의 컴파일 전 단계로 구현되지 않음
  - 본질적으로 렉서의 일부임
  - gcc도 유사한 방식을 사용할 것이라고 생각함
  - 매크로 이름에 접근하는 것은 기술적으로 불가능하지 않음
  - 수요가 많지 않기 때문에 구현되지 않음

- D 언어에서 ImportC를 사용하여 유사한 작업을 수행하는 방법을 블로그에 작성함
  - [블로그 링크](https://www.davidpriver.com/C-macro-reflection-in-D.html)

- 각 enum마다 최소 UINT16_MAX*sizeof(intptr_t) 바이트를 실행 파일에 추가할 것 같음

- 함수 정의가 매우 읽기 쉽게 보임
  - 다른 언어에서 본 적이 있지만 보통은 매우 끔찍함
  - Zig를 배울 가치가 있을지도 모름
  - 이것은 킬러 기능임

- 사이트가 마음에 듦
  - Zig가 정말로 인기를 끌고 있는 것 같음
