1
2

More than 3 years have passed since last update.

PythonでC(++)のヘッダファイル(.h)からマクロ定数を取得

Last updated at Posted at 2019-11-15

「PythonとC++で定数を共有したい,かつC++側の定数はコンパイル時に確定させたい,かつPythonでも同じ変数を使いたい」という特異な例があったのでメモ.

Pythonから.hで定義された

sample.h
#ifndef _PARAM
#define _PARAM

#define NUM 10
#define epoch 100

#endif

と言うような定数を取り出す.今回は,const intなどで定義したグローバル変数は場合分けがめんどくさいので考えません.

def read_header_and_get_macro(header_filepath):
    with open(header_filepath, mode='r') as f:
        lst = [s.strip() for s in f.readlines()]
    comment_flg = False
    for l in lst:
        items = l.split()
        if len(items) != 0 and items[0] == "/*":
            comment_flg = True
            continue
        if comment_flg == True:
            if len(items) != 0 and items[0] == "*/":
                comment_flg = False
            continue
        if len(items) < 2 or items[0] != "#define":
            continue
        if items[1] in globals():
            if items[2] == 'true':
                globals()[items[1]] = True
            elif items[2] == 'false':
                globals()[items[1]] = False
            else:
                try:
                    globals()[items[1]] = float(items[2])
                except ValueError:
                    try:
                        globals()[items[1]] = int(items[2])
                    except ValueError:
                        globals()[items[1]] = items[2]

やっていること

3行目
    lst = [s.strip() for s in f.readlines()]

ファイルを読み込んで行ごとにリストにする.今回は行ごとのリストをとってきてそれをリストで回したけど別にf.readline()をfor文回すのは自由

4行目
    comment_flg = False

C(++)では/*から始まって*/で終わるまでの間は全てコメントなので,これを覚えておくためのフラグ.

6行目
        items = l.split()

行の中身について,半角スペースなどでわけられているところを分けたリストを取得.

['#define', 'NUM', '10']

みたいなリストがほしかった.

7行目~13行目
        if len(items) != 0 and items[0] == "/*":
            comment_flg = True
            continue
        if comment_flg == True:
            if len(items) != 0 and items[0] == "*/":
                comment_flg = False
            continue

上記の通り,コメントを除く.

14行目~15行目
        if len(items) < 2 or items[0] != "#define":
            continue

#defineから始まらない行はマクロを定義していないので除く.

16行目~28行目
        if items[1] in globals():
            if items[2] == 'true':
                globals()[items[1]] = True
            elif items[2] == 'false':
                globals()[items[1]] = False
            else:
                try:
                    globals()[items[1]] = float(items[2])
                except ValueError:
                    try:
                        globals()[items[1]] = int(items[2])
                    except ValueError:
                        globals()[items[1]] = items[2]

今までのもの以外のものが定数のはずです.このとき, items[1]には定数名が入っているはずなので,これがグローバル変数として定義されているかチェックするためにitems[1] in globals()をします.もしも定義されていれば, globals()[items[1]]でその値がわかるので,変数を強制的に書き換えれば完成.ですが,C++のbool型をPythonにそろえてあげる処理をしているのと,float/int/strの変換も行っています.

1
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2