【问题标题】:Looking for C/C++ pre-processor macro or template to reverse a hex macro array and generate hex number寻找 C/C++ 预处理器宏或模板来反转十六进制宏数组并生成十六进制数
【发布时间】:2020-04-17 07:53:28
【问题描述】:

我有一个非常具体的问题。我有以下宏定义以供稍后在代码中使用。

#define MY_ARRAY { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 \
                   0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}

现在我想在编译期间反转排序并生成一个值,以便在编译期间直接嵌入到可执行文件中。所以基本上,我想要下面的代码

long x = DO_IT(MY_ARRAY);
long y = DO_TOO(MY_ARRAY);

这样在编译时

x = 0x7766554433221100;
y = 0xFFEEDDCCBBAA9988;

我的 DO_ITDO_TOO 必须是什么样子才能正常工作?我真的在这个问题上苦苦挣扎,似乎找不到可行的解决方案。非常感谢任何帮助。

【问题讨论】:

  • 你的数组总是有相同的元素吗?你能修改你的MY_ARRAY 宏,使它不包含大括号吗?为什么要使用宏而不是函数?
  • 它实际上包含 16 个元素(我会更新问题)。 64 位十六进制数。它确实包含大括号,因为稍后在我正在处理的遗留代码中需要它。
  • #define reverse(a, b) b, a ? DO_IT 是不可能的 - 不可能在预处理器中删除 { }。您可以删除 { } 吗?还有0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF怎么了?
  • 但这不适合 64 位 int;你需要128位。如果您可以分两个阶段定义MY_ARRAY - 一个不带大括号,另一个带大括号 - 然后您可以使用 bt-shifting 创建数字:#define(A0, A1, ...) (((A0) << 0) | ((A1) << 8) | ...)
  • C 和 C++ 是不同的语言,C++ 可以进行比 C 更复杂的编译时计算(不基于宏)。选择您的语言。

标签: c++ c c-preprocessor


【解决方案1】:

如果你删除 { } 你可以:

#define MY_ARRAY  0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77
#define DO_IT_2(_0,_1,_2,_3,_4,_5,_6,_7)  (\
     (unsigned long long)(_7) << (7 * 8) | \
     (unsigned long long)(_6) << (6 * 8) | \
     etc...            \
     (unsigned long long)(_0) << (0 * 8))
#define DO_IT(x)  DO_IT_2(x)

更新:

#define MY_ARRAY2 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
               0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
#define REVERSE_LL_8(_0,_1,_2,_3,_4,_5,_6,_7)  (\
     (unsigned long long)(_7) << (7 * 8) | \
     (unsigned long long)(_6) << (6 * 8) | \
     etc...            \
     (unsigned long long)(_0) << (0 * 8))
#define DO_IT_2(_0,_1,_2,_3,_4,_5,_6,_7,...)  \
        REVERSE_LL_8(_0,_1,_2,_3,_4,_5,_6,_7)
#define DO_IT(x) DO_IT_2(x)
#define DO_TOO_2(a0,a1,a2,a3,a4,a5,a6,a7,_0,_1,_2,_3,_4,_5,_6,_7)  \
        REVERSE_LL_8(_0,_1,_2,_3,_4,_5,_6,_7)
#define DO_TOO(x) DO_TOO_2(x)

DO_IT(MY_ARRAY2)
DO_TOO(MY_ARRAY2)

所以我可以使用 C++ 功能

在 C++ 中,这是一个非常简单的 contexpr 函数和 initializer_list

#include <initializer_list>
#define MY_ARRAY  {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}
constexpr unsigned long long DO_IT(const std::initializer_list<int>& l) {
    unsigned long long r = 0;
    for (auto&& i : l) {
        r >>= 8;
        r |= (unsigned long long)i << (7 * 8);
    }
    return r;
}
constexpr long a = DO_IT(MY_ARRAY);

【讨论】:

  • 好的,是的。实际上,我可以删除大括号并通过旧代码的另一个宏添加它们,基本上像这样使用 MY_ARRAY_RAW,然后让 MY_ARRAY 成为 { MY_ARRAY_RAW }。我会试试的。谢谢!
  • 谢谢!!!它使用宏工作。我不得不做一些改变,因为我使用的是 MSVC,并且在扩展参数时没有遵守标准。我找到了一个解决方案:stackoverflow.com/questions/35210637/…
【解决方案2】:

似乎没有任何理由在这里使用宏,您只需要编译时评估:

#include <stdio.h>
#include <stdint.h>

#define MY_INIT_LIST { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, \
                       0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, }
#define MY_ARRAY (const uint32_t[]) MY_INIT_LIST

int main (void) 
{
  for(size_t i=0; i<16; i++)
    printf("%X ", MY_ARRAY[i]);

  const uint32_t u32 = MY_ARRAY[3] << 24 |
                       MY_ARRAY[2] << 16 |
                       MY_ARRAY[1] <<  8 |
                       MY_ARRAY[0] <<  0 ;
  printf("\n%X\n", u32);
}

这是独立于字节序的标准 C。它可以简单地重写为使用 64 位类型,这可能是(?)你真正想要的?

【讨论】:

    【解决方案3】:

    请看一下 Boost 库的解决方案: https://www.boost.org/doc/libs/1_68_0/libs/preprocessor/doc/ref/array_reverse.html

    BOOST_PP_ARRAY_REVERSE 是您所需要的。

    【讨论】:

    • 感谢您的建议,但如果我能提供帮助,我宁愿不添加 boost 库。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-26
    • 2018-02-01
    • 1970-01-01
    • 2017-08-12
    • 2011-06-01
    • 2018-11-18
    相关资源
    最近更新 更多