2012-10-02 74 views
1

替换索引字符数组我有一个已知的预定组调用一个函数使用预处理器

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

什么我希望做的是像

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

为了在编译之前将整个东西替换为整数,我可以关闭该值,而不必存储字符串或在运行时进行比较。 我意识到我们不能在预处理器中做到这一点,但只是想知道是否有人遇到了解决这个看似可解决的问题的一些漂亮方法。

+0

对宏的参数是字符串是重要的吗?难道不就是'FUNC_A(ABCD); FUNC_A(EFGH);'用令牌而不是字符串? –

+0

是啊,不幸的是我需要使用除预处理器无法处理的字母之外的符号(例如。==,> schuess

+0

我能想到的唯一的事情就是在编译之前替换它们的自定义分析器,但我真的不想更改信息来源 – schuess

回答

1

如果你需要,你可以手工比较,但这会很乏味。为简单起见,让我们假设我们想这样做的字符串"AB"

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

这将返回1当字符串等于"AB"0否则,也照顾该字符串的长度是否正确的,不能访问超出数组范围等。

您唯一需要担心的是参数X被多次评估。如果你传递一个字符串文字,这不是问题,但是对于带有副作用的表达式。

对于字符串文字任何体面的编译器应该能够在编译时替换这样的表达式。

+0

您确定您确实想要将它变成'&&(X)[2]'? – ArjunShankar

+0

@ArjunShankar,是的,'(X)[2]'测试这个字节是否为'0',换句话说,如果字符串的长度为2. –

+0

这就是我想指出的:http:// codepad 。org/7nVPuE3C – ArjunShankar

0

就像你所描述的那样,避免字符串和运行时比较,我只能想到一个预处理器。在Unix环境下,我会尝试使用bash脚本对预处理器进行简单的包装,然后使用sed或awk替换所提及的函数和参数,然后调用真正的cpp预处理器。我认为这只是一个快速入侵。

更新:在linux和gcc中,执行后处理器似乎更容易,因为我们可以替换生成的.i文件(但我们通常不能用原始的.c文件来做)。为此,我们可以制作一个cc1封装。

警告:这是另一个危险和丑陋的破解。另见Custom gcc preprocessor

这是一个用于做这件事的cc1包装。这是Linux下的bash脚本和gcc 4.6:

#!/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:[email protected]" 
#echo "getfile=$getfile" 
#echo "ifile=$ifile" 

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

exit $rc 

如何使用它:使用标志调用gcc的-B(目录,其中CC1包装居住)和--no集成-CPP