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 环境中,我会尝试使用 bash 脚本对预处理器进行简单的包装,该脚本又使用 sed 或 awk 替换提到的函数和参数,然后调用真正的 cpp 预处理器。我认为这只是一个快速破解。

更新:在 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 回答