我想找到一种最有效的方法来计算包含C ++ 11中char
的最低有效位的int
。该解决方案必须适用于任何可能符合标准的编译器。 (我使用的是N3290 C ++草案规范,基本上是C ++ 11。)
这样做的原因是我正在编写类似于模糊测试器的东西,并希望检查需要std::string
作为输入的库。所以我需要为字符串生成随机字符。我正在使用的伪随机生成器提供了低位非常随机的int,但我不确定确切的范围。 (基本上,确切的范围取决于“测试用例的大小”运行时参数。)
如果我不关心任何编译器的工作,那就简单如下:
inline char int2char(int i) { return i; }
在你将此视为一个微不足道的问题之前,请考虑:
您不知道char
是有签名还是无签名类型。
如果char
已签名,则从无法代表的int
到char
的转换是“实现定义的”(§4.7/ 3)。这比 undefined 要好得多,但是对于这个解决方案,我需要看到一些证据表明该标准禁止将所有内容转换为CHAR_MIN
和CHAR_MAX
之间的内容。 {1}}。
'\0'
(第5.2.10节)。 reinterpret_cast
执行与上一点相同的转化。
static_cast
- 尽管它会使某些编译器警告静音 - 但对于所有实现定义的转换几乎肯定不正确。特别是,char c = i & 0xff;
始终为正数,因此如果i & 0xff
已签名,则可能无法将c
的负值转换为i
的负值。< / p>
以下是一些可行的解决方案,但在大多数情况下,我担心它们不如简单的转换效率高。对于这么简单的事情来说,这些看起来也太复杂了:
在指针或引用上使用c
,因为您可以从reinterpret_cast
或unsigned char *
转换为unsigned char &
或char *
(但在可能的运行时开销成本。)
使用char &
和char
的联合,首先将unsigned char
分配给int
,然后提取unsigned char
(再次可能会慢一点。
向左和向右移动以签署扩展int。例如,如果char
是int,则运行i
(但这不太优雅,如果编译器没有优化转换,那么速度很慢)。
这是一个最小的工作示例。目标是争辩说断言永远不会在任何编译器上失败,或者定义一个断言永远不会失败的备用c = ((i << 8 * (sizeof(i) - sizeof(c)) >> 8 * (sizeof(i) - sizeof(c))
。
int2char
我用C ++表达了这个问题,因为标准更容易在网上找到,但我对C中的解决方案同样感兴趣。这是C中的MWE:
#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstdlib>
using namespace std;
constexpr char int2char(int i) { return i; }
int
main(int argc, char **argv)
{
for (int n = 1; n < min(argc, 127); n++) {
char c = -n;
int i = (atoi(argv[n]) << 8) ^ -n;
assert(c == int2char(i));
}
return 0;
}
答案 0 :(得分:0)
更好的方法是使用一个字符数组并生成一个随机数来从该数组中选择一个字符。这样你就可以获得“表现良好”的角色;或至少具有明确不良的字符。如果你真的想要所有256个字符(注意8位假设),那么创建一个包含256个条目的数组('a','b',......'\ t','n'.....)< / p>
这也是便携式的
答案 1 :(得分:0)
鉴于您似乎对位值感兴趣(而不是数字值),并且还要求C解决方案,我将发布我的内容相信是符合要求和最佳的东西:
inline char int2char(int i) {
char ret;
memcpy(&ret, (char *)&i + OFFSET, 1);
return ret;
}
其中OFFSET
是根据字节顺序检查扩展为0
或sizeof(int)-1
的宏。
AFAICS,无论char
是有符号还是无符号,代表用于负值,还是char
或int
的宽度都是不变的。它不依赖于任何奇怪的类型 - 惩罚技巧,也没有分支或复杂的操作(例如除法)。
我说“最优”,因为我假设任何理智的编译器都将memcpy
视为内在的,因此会做一些聪明的事情。