我有这些小函数,它们接受一个小的 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 没有区别?
使用 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;
}
case
标签的值必须是常量表达式,像(*((int*)x))
这样的表达式不符合条件。您使用 #define
的事实并不重要。
你需要为此使用
if
...else
链。
if (something == HASH4("FOOD")) {
printf("Food!");
} else if (something == HASH8("SEXYCOOL")) {
printf("Sexycool!");
}
更新:@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;
}
待办事项:
constexpr
功能来做到这一点。