【问题标题】:Replace char arrays with an index using pre-processor使用预处理器将 char 数组替换为索引
【发布时间】:2012-10-02 14:51:10
【问题描述】:

我有一组已知的、预定的函数调用

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

而我希望做的是像

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

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

【问题讨论】:

  • 宏的参数是字符串重要吗?难道不能只是 FUNC_A(ABCD); FUNC_A(EFGH); 用标记而不是字符串吗?
  • 是的,不幸的是,除了预处理器无法处理的字母之外,我还需要使用符号(例如 ==、>
  • 我唯一能想到的是自定义解析器在编译前替换它们,但我真的不想更改源

标签: c c-preprocessor


【解决方案1】:

如果需要,您可以手工进行比较,但这会很乏味。为简单起见,让我们假设我们要对字符串 "AB" 执行此操作:

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

这将在字符串等于"AB"0 时返回1,否则,还要注意字符串的长度是否正确,不要超出数组边界等访问。

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

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

【讨论】:

  • 你确定你的意思是&& (X)[2]
  • @ArjunShankar,是的,(X)[2] 测试该字节是否为0,或者换句话说,如果字符串的长度为 2。
  • @ArjunShankar,是的,你是对的,应该是 !(X)[2],已更正。
【解决方案2】:

为了按照您的描述进行操作,避免字符串和运行时比较,我只能想到一个预处理器。是否只是为了快速破解,在 Unix 环境中,我会尝试使用 bash 脚本对预处理器进行简单的包装,该脚本又使用 sed 或 awk 替换提到的函数和参数,然后调用真正的 cpp 预处理器。我认为这只是一种快速破解。

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

警告:这是另一个危险和丑陋的黑客攻击。另见Custom gcc preprocessor

这是用于执行此操作的 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

如何使用它:使用标志调用gcc -B(cc1包装器所在的目录)和--no-integrated-cpp

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-08
    • 1970-01-01
    • 1970-01-01
    • 2017-08-08
    相关资源
    最近更新 更多