1

関数への既知の事前定義された一連の呼び出しがあります

FUNC_A("ABCD");
FUNC_A("EFGH");

そして、私がやりたいと思っていたのは、次のようなものでした

#define FUNC_A("ABCD")     0
#define FUNC_A("EFGH")     1
#define FUNC_A(X)          0xFF

そのため、コンパイル前にすべてが整数に置き換えられ、値をオフにして、文字列を保存したり、実行時に比較を行ったりする必要がなくなります。プリプロセッサではこれを行うことができないことはわかっていますが、この一見解決可能な問題を回避するための気の利いた方法に誰かが遭遇したかどうか疑問に思っていました.

4

2 に答える 2

1

必要に応じて比較を手作りすることもできますが、これは面倒です。簡単にするために、文字列に対してそれを実行したいとします"AB"

#define testAB(X) ((X) && (X)[0] == 'A' && (X)[1] == 'B' && !(X)[2])

1これは、文字列が等しいかそう"AB"でない場合に返され0ます。また、文字列が正しい長さであり、配列の境界を超えてアクセスしないように注意してください。

あなたが心配しなければならない唯一のことは、引数Xが複数回評価されるということです。文字列リテラルを渡す場合、これは問題ではありませんが、副作用のある式の場合は問題になります。

文字列リテラルの場合、適切なコンパイラはコンパイル時にそのような式を置き換えることができるはずです。

于 2012-10-02T16:45:53.333 に答える
0

あなたが説明したように、文字列と実行時の比較を回避するために、私はプリプリプロセッサしか考えられません。Unix 環境では、sed または awk を使用して前述の関数と引数を置き換え、実際の cpp プリプロセッサを呼び出す bash スクリプトを使用して、プリプロセッサの単純なラッパーを試してみます。これは簡単なハックだと思います。

更新: Linux と gcc では、生成された .i ファイルを置き換えることができるため、ポスト プリプロセッサを実行する方が簡単なようです (ただし、通常、元の .c ファイルでそれを行うことはできません)。そのために、cc1 ラッパーを作成できます。

警告: これは別の危険で醜いハックです。カスタム gcc プリプロセッサも参照してください

これは、それを行うための cc1 ラッパーです。Linux および gcc 4.6 用の bash スクリプトです。

#!/bin/bash
# cc1 that does post preprocessing on generated .i files, replacing function calls
#
# note: doing post preprocessing is easier than pre preprocessing, because in post preprocessing we can replace the temporary .i file generated by the preprocessor (in case of doing pre preprocessing, we should change the original .c file -this is unacceptable-; or generate a new temp .c file with our preprocessing before calling the real preprocessor, but then eventual error messages are now referring to the temp .c file..)

convert ()
{  
    local i=$1
    local o=$2

    ascript=$(cat <<- 'EOAWK'
    {
            FUNCT=$1; 
            ARGS=$2; 
            RESULT=$3; 
            printf "s/%s[ \\t]*([ \\t]*%s[ \\t]*)/%s/g\n", FUNCT, ARGS, RESULT;
    } 
EOAWK
    )

    seds=$(awk -F '|' -- "$ascript" << EOFUNCS
FUNC_A|"ABCD"|0
FUNC_A|"EFGH"|1
FUNC_A|X|0xFF
EOFUNCS
    )

    sedfile=$(mktemp --tmpdir prepro.sed.XXX)
    echo -n "$seds" > "$sedfile"

    sed -f "$sedfile" "$i" > "$o"
    rc=$?

    rm "$sedfile"

    return $rc
}

for a
do 
    if [[ $a = -E ]]
    then
            isprepro=1
    elif [[ $isprepro && $a = -o ]]
    then   
            getfile=1
    elif [[ $isprepro && $getfile && $a =~ ^[^-].*[.]i ]]
    then
            ifile=$a
            break
    fi
done

#echo "args:$@"
#echo "getfile=$getfile"
#echo "ifile=$ifile"

realcc1=/usr/lib/gcc/i686-linux-gnu/4.6/cc1
$realcc1 "$@"
rc=$?
if [[ $rc -eq 0 && $isprepro && $ifile ]]
then
    newifile=$(mktemp --tmpdir prepro.XXX.i)
    convert "$ifile" "$newifile" && mv "$newifile" "$ifile"
fi

exit $rc

使用方法: フラグ-B (cc1 ラッパーが存在するディレクトリ) および--no-integrated-cppを使用して gcc を呼び出します。

于 2012-10-03T14:14:43.163 に答える