2012-10-02 71 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