在c++中将int的最低有效位放入char中
Place least significant bits of int into char in C++
我想找到一种最有效的方法来计算包含c++ 11中int
的最低有效位的char
。解决方案必须与任何可能的标准兼容的编译器一起工作。(我使用的是N3290 c++草案规范,本质上是c++ 11)
这样做的原因是我正在编写类似于模糊测试器的东西,并且想要检查需要std::string
作为输入的库。所以我需要为字符串生成随机字符。我使用的伪随机生成器提供了整数,其低位是均匀随机的,但我不确定确切的范围。(基本上确切的范围取决于"测试用例的大小"运行时参数。)
如果我不关心在任何编译器上工作,这将像这样简单:
inline char int2char(int i) { return i; }
在你认为这是一个微不足道的问题之前,考虑一下:
您不知道
char
是有符号类型还是无符号类型如果
char
是有符号的,那么从不可表示的int
到char
的转换是"实现定义的"(§4.7/3)。这比undefined好得多,但是对于这个解决方案,我需要看到一些证据,证明标准禁止将所有不在CHAR_MIN
和CHAR_MAX
之间的整数转换为' '
。reinterpret_cast
不允许在有符号和无符号字符之间使用(§5.2.10)。static_cast
执行与前一点相同的转换char c = i & 0xff;
——尽管它沉默了一些编译器警告——几乎肯定不是对所有实现定义的转换都是正确的。特别是,i & 0xff
总是一个正数,因此在c
有符号的情况下,很可能不会将i
的负值转换为c
的负值。
这里有一些确实有效的解决方案,但在大多数情况下,我担心它们不会像简单的转换那样有效。对于这么简单的东西来说,这些看起来也太复杂了:
在指针或引用上使用
reinterpret_cast
,因为您可以从unsigned char *
或unsigned char &
转换为char *
或char &
(但可能以运行时开销为代价)。使用
char
和unsigned char
的联合,首先将int
分配给unsigned char
,然后提取char
(这再次可能会更慢)。向左和向右移动以对int进行符号扩展。例如,如果
i
是int,运行c = ((i << 8 * (sizeof(i) - sizeof(c)) >> 8 * (sizeof(i) - sizeof(c))
(但这是不优雅的,如果编译器没有优化移位,相当慢)。
下面是一个最小的工作示例。目的是论证断言在任何编译器上都不会失败,或者定义一个替代的int2char
,其中断言永远不会失败。
#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;
}
我用c++来表达这个问题,因为在网上更容易找到标准,但我对C的解决方案同样感兴趣。下面是C中的MWE:
#include <assert.h>
#include <stdlib.h>
static char int2char(int i) { return i; }
int
main(int argc, char **argv)
{
for (int n = 1; n < argc && n < 127; n++) {
char c = -n;
int i = (atoi(argv[n]) << 8) ^ -n;
assert(c == int2char(i));
}
return 0;
}
一个更好的方法是有一个字符数组,并生成一个随机数从该数组中选择一个字符。这样你就会得到"表现良好"的角色;或者至少是有明确定义的坏的角色。如果你真的想要所有256个字符(注意8位假设),那么创建一个包含256个条目的数组('a','b',....'t','n'.....)
这也是可移植的
鉴于您似乎对位值(而不是数字值)感兴趣,并且还要求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
视为内在的,因此会在这里做一些聪明的事情。
- 最高有效数字侧的第N位
- 如果变量名称不跟在 char* 后面,const char* 是否有效?
- 如何在整数中找到最低有效位(LSB)的位置?c ++
- 将一个数字拆分为多个数字,每个数字只有一个有效位
- 验证用户输入是否有效 [从 'char' 到 'char*' 的转换无效]
- 最高有效位基数排序如何比最低有效位基数分类更有效
- 如何在C++中获得整数的j个最高有效位
- C++找到二进制数的最高有效位
- 从 8 位值中获取最高有效位
- 如何创建一个32位int和四个8位char类型的并集,每个类型都引用32位int的差分片
- 将文件的一部分读取到 std::vector 中的有效方法<char>?
- 如何将最低有效位写入缓冲区
- 将数据存储在指针的最高有效位中
- GLib类型的位大小和可移植性更奇特(想想16位char)的平台
- 修改双精度的最低有效位(Java和c++)
- 在c++中将int的最低有效位放入char中
- C/ c++中最低有效位(LSB)和最高有效位(MSB)的校验值
- 是否设置了最高有效位
- 将不相关的数据存储在指针的最低有效位是否可靠
- C/ c++中最低有效位集的有效除法