使用 char[4] 或 char[8] 作为常量 int?

问题描述 投票:0回答:3

我有这些小函数,它们接受一个小的 char 数组并将其重铸为 int 或 longlong:

#define HASH4(x) (*((int*)x))
#define HASH8(x) (*((longlong*)x))

int aValue=HASH4("FOOD");
longlong aBigValue=HASH8("SEXYCOOL");

我想知道 C/C++ 语法中是否有任何方法可以让我在不需要 #define 的情况下执行此操作?原因是,我想在 case 结构中使用它们,如下所示:

switch(something)
{
case HASH4("FOOD"): printf("Food!");break;
case HASH8("SEXYCOOL"): printf("Sexycool!");break;
}

...哪个,它不会让我做的。

那么在 c 语法中是否有某种方式告诉它把这个四字节的 char* 解释为一个 int?或者,或者,某种方式来编写转换它的定义?

澄清:我想知道 C/C++ 语法中是否有一种方法可以获取四个字节,以便这两个语句等价:

int something=Magic("\0\0\0A");
int something=65;

switch(stuff)
{
    case Magic("FOOD"): <-- becomes valid
}

...因为我们都知道 const char "FOOD" 只是包含 70,79,79,68 的四个字节...是否有某种方法可以包装一个漂亮的 MAKEINT(4 字节),它完全由预处理器处理或者在其他方面与 int 或 long long 没有区别?

c++ c-preprocessor
3个回答
2
投票

使用 constexpr 函数代替宏。例如

#include <string_view>
#include <utility>
#include <array>
#include <iostream>

// create a constexpr hash function which may
// be used both at compile and at runtime.
// I used std::string_view since I am used to that.
// but you can also use a char* and use strlen

static constexpr auto hash(const std::string_view& str)
{
    std::array<std::size_t, 4> primes{ 1,3,5,7 };
    std::size_t count = std::min(primes.size(), str.size());

    std::size_t hash{ 0ul };
    for (std::size_t n = 0; n < count; n++)
    {
        hash += (primes[n] * static_cast<std::size_t>(str[n]));
    }

    return hash;
}

int main()
{
    std::size_t something = hash("FOOD");

    switch (something)
    {
        case hash("FOOD"): std::cout << "Food!"; break;
        case hash("SEXYCOOL"): std::cout << "Sexycool!"; break;
    }

    return 0;
}

1
投票

case
标签的值必须是常量表达式,像
(*((int*)x))
这样的表达式不符合条件。您使用
#define
的事实并不重要。

你需要为此使用

if
...
else
链。

if (something == HASH4("FOOD")) {
    printf("Food!");
} else if (something == HASH8("SEXYCOOL")) {
    printf("Sexycool!");
}

1
投票

更新:@chtz 的 hack 完全有效。它诱使编译器没有意识到它正在从 char 数组构建一个 int。

test.cpp:

///usr/bin/env ccache g++ -Wall -Wextra -Werror -O3 -std=gnu++17 "$0" -o /tmp/a && /tmp/a "$@"; exit
// For the line just above, see my answer here: https://stackoverflow.com/a/75491834/4561887

#include <iostream>

#define HASH4(s) ((((s)[0]*256+(s)[1])*256+(s)[2])*256+(s)[3])

void check_int(int i)
{
    switch(i)
    {
    case HASH4("FOOD"):
        printf("FOOD\n");
        break;
    case HASH4("TREE"):
        printf("TREE\n");
        break;
    }
}

int main()
{
    std::cout << "Test\n";

    int something = HASH4("FOOD");
    printf("something = %i\n", something); // something = 1179602756
    check_int(something);

    something = 1179602756;
    check_int(something);


    // ----------------------------
    // withOUT using a #define now
    // ----------------------------

    something = ((('F'*256+'O')*256+'O')*256+'D');

    switch(something)
    {
        case ((('F'*256+'O')*256+'O')*256+'D'):
            printf("FOOD\n");
            break;
    }


    return 0;
}

运行命令:

chmod +x test.cpp   # make executable
./test.cpp          # run it

输出:

Test
something = 1179602756
FOOD
FOOD
FOOD

Without 使用

#define
:这很好用,因为
((('F'*256+'O')*256+'O')*256+'D')
是一个常量表达式!——它在编译时完全计算为一个常量值。

其他信息

要使 4 个字节被解释为一个常量 4 字节 int (

const int32_t
),只需使用

// this
#define CONST_INT32(bytes) (*((const int32_t*)(bytes)))

// instead of this
#define CONST_INT32(bytes) (*((int32_t*)(bytes)))

即:在您的指针投射之前添加

const

但是,这会得到一个

const int32_t
not
constexpr int32_t
常量表达式 int32_t 相同。 常量表达式 告诉编译器这块内存不会被玩弄、编辑或重新解释为另一种类型。您通过宏将 4 个字节重新解释为 int 的事实已经违反了这一点。

所以,不,在 C++ 中,我知道没有预处理器宏方式强制将 4 个字节解释为

constexpr int
.

您可以将 4 个字节重新解释为

const int
,但这不是一回事。只有
constexpr
类型可以用作switch 语句中的case,所以@dbush 的答案 是正确的。使用
if
else
来检查
const int
值。

注意:如果您声明一个

const int
,编译器可能会看到它也可能是一个
constexpr int
并为您做出决定。所以,这运行:

#include <iostream>

int main()
{
    std::cout << "Test\n";

    const int CASE1 = 7; // compiler sees these could also be constexpr
    const int CASE2 = 8; // compiler sees these could also be constexpr

    int something = CASE1;

    switch(something)
    {
    case CASE1:
        printf("CASE1\n");
        break;
    case CASE2:
        printf("CASE2\n");
        break;
    }

    return 0;
}

...还有这个:

#include <iostream>

int main()
{
    std::cout << "Test\n";

    constexpr int CASE1 = 7; // you are explicitly making these constexpr
    constexpr int CASE2 = 8; // you are explicitly making these constexpr

    int something = CASE1;

    switch(something)
    {
    case CASE1:
        printf("CASE1\n");
        break;
    case CASE2:
        printf("CASE2\n");
        break;
    }

    return 0;
}

待办事项:

  1. [ ] 添加一些
    constexpr
    功能来做到这一点。
© www.soinside.com 2019 - 2024. All rights reserved.