我正在为 ROM 非常有限的目标编写C代码(不是 c++),但我希望代码易于使用#defines 为其他类似目标自定义。我有 #defines 用于指定设备的地址和其他值,但作为一种代码节省技术,这些值必须按位反转。我可以通过首先手动反转它们来输入它们,但这会为将来的使用造成混淆。我可以定义某种执行按位反转的宏吗?
问问题
372 次
4 回答
3
如此处所示(C 中位反转的最佳算法(从 MSB->LSB 到 LSB->MSB)),没有单一的操作可以切换 c 中的顺序。因此,如果您要创建一个#define
宏来执行操作,它实际上会在每次使用时执行相当多的工作(如果经常使用,还会显着增加二进制文件的大小)。我建议手动创建其他有序常量,并仅使用清晰的文档来确保有关它们的信息不会丢失。
于 2013-10-25T15:01:12.313 回答
1
为了代码可读,我不推荐它,但你可以做类似的事情
#define NUMBER 2
#define BIT_0(number_) ((number_ & (1<<0)) >> 0)
#define BIT_1(number_) ((number_ & (1<<1)) >> 1)
#define REVERSE_BITS(number_) ((BIT_1(number_) << 0) + (BIT_0(number_) << 1))
int main() {
printf("%d --> %d", NUMBER, REVERSE_BITS(NUMBER));
}
于 2013-10-25T15:08:33.337 回答
1
有这种操作的技术(例如,参见Boost Preprocessor库),但大多数时候最简单的解决方案是使用以某种语言编写的外部预处理器,其中位操作更容易。
例如,这是一个小 Python 脚本,它将替换 @REV(xxxx)@ 的所有实例,其中 xxxx 是一个十六进制字符串,具有相同长度的位反转常量:
#!/bin/python
import re
import sys
reg = re.compile("""@REV\(([0-9a-fA-F]+)\)@""")
def revbits(s):
return "0X%x" % int(bin(int(s, base=16))[-1:1:-1].ljust(4*len(s), '0'), base=2)
for l in sys.stdin:
sys.stdout.write(reg.sub(lambda m: revbits(m.group(1)), l))
这是 awk 中的一个版本:
awk 'BEGIN{R["0"]="0";R["1"]="8";R["2"]="4";R["3"]="C";
R["4"]="2";R["5"]="A";R["6"]="6";R["7"]="E";
R["8"]="1";R["9"]="9";R["A"]="5";R["B"]="D";
R["C"]="3";R["D"]="B";R["E"]="7";R["F"]="F";
R["a"]="5";R["b"]="D";R["c"]="3";R["d"]="B";
R["e"]="7";R["f"]="F";}
function bitrev(x, i, r) {
r = ""
for (i = length(x); i; --i)
r = r R[substr(x,i,1)]
return r
}
{while (match($0, /@REV\([[:xdigit:]]+\)@/))
$0 = substr($0, 1, RSTART-1) "0X" bitrev(substr($0, RSTART+5, RLENGTH-7)) substr($0, RSTART+RLENGTH)
}1' \
<<<"foo @REV(23)@ yy @REV(9)@ @REV(DEADBEEF)@"
foo 0X32 yy 0X9 0Xfeebdaed
于 2013-10-25T15:27:18.880 回答
1
我认为这样的事情应该有效:
#define REV2(x) ((((x)&1)<<1) | (((x)>>1)&1))
#define REV4(x) ((REV2(x)<<2) | (REV2((x)>>2)))
#define REV8(x) ((REV4(x)<<4) | (REV4((x)>>4)))
#define REV16(x) ((REV8(x)<<8) | (REV8((x)>>8)))
#define REV32(x) ((REV16(x)<<16) | (REV16((x)>>16)))
它仅使用对常量表达式都是安全的简单操作,并且编译器很可能会在编译时评估这些操作。
您可以通过在需要常量表达式的上下文中使用它们来确保在编译时对它们进行评估。例如,您可以初始化一个静态变量或声明一个枚举:
enum {
VAL_A = SOME_NUMBER,
LAV_A = REV32(VAL_A),
};
于 2013-10-25T18:38:28.593 回答