Cの定数値や型のサイズを取得するための関数

sb-alienパッケージとかを使ってネイティブライブラリを使用していると、ちょくちょくCの定数の値や型の定義(型のサイズ)を知りたくなることがある。
毎回ヘッダファイルを調べるのも面倒なので、lisp上から取得出来るように関数を用意してみた。

(defun c-inspect (&key include type value)       
  (flet ((gen-source ()
           (with-output-to-string (out)
             (format out "~&#include <iostream>~%")
             (dolist (inc include)
               (format out "~&#include <~a>~%" inc))

             (format out "~%int main() {~%")
             (dolist (ty type)
               (format out "  std::cout << \"sizeof(~a) = \" << sizeof(~a) << std::endl;~%" ty ty))

             (dolist (val value)
               (format out "  std::cout << \"~a = \" << ~a << std::endl;~%" val val))
             
             (format out "}~%"))))
    ;; 定数や型の情報を出力するためのC++ソースを生成
    (with-input-from-string (in (gen-source))
      ;; 生成したソースをコンパイル 
      (let ((ret (sb-ext:run-program "g++" `("-x" "c++" "-" "-o" "/tmp/c.inspect.tmp")
                                     :search t :input in :output t)))
        ;; コンパイルに成功しているなら、コマンドを実行
        (when (zerop (sb-ext:process-exit-code ret))
          (sb-ext:run-program "/tmp/c.inspect.tmp" '() :output t)))))
  (values))

使用例。

> (c-inspect :type '("int" "unsigned long" "void *") :value '("NULL"))
sizeof(int) = 4
sizeof(unsigned long) = 8
sizeof(void *) = 8
NULL = 0

> (c-inspect :include '("sys/socket.h") :value '("PF_UNIX" "SO_ACCEPTCONN" "SO_ERROR"))
PF_UNIX = 1
SO_ACCEPTCONN = 30
SO_ERROR = 4

;; エラー
> (c-inspect :type '("undefined_type"))
<stdin>: In function ‘int main()’:
<stdin>:4: error: ‘undefined_type’ was not declared in this scope