如何在 C/C++ 中随机翻转 char 的二进制位
Posted
技术标签:
【中文标题】如何在 C/C++ 中随机翻转 char 的二进制位【英文标题】:How to random flip binary bit of char in C/C++ 【发布时间】:2014-06-12 10:13:50 【问题描述】:如果我有一个字符数组A
,我用它来存储十六进制
A = "0A F5 6D 02" size=11
这个char数组的二进制表示是:
00001010 11110101 01101101 00000010
请问有什么函数可以随机翻转位吗?
即: 如果参数是5
00001010 11110101 01101101 00000010
-->
10001110 11110001 01101001 00100010
它会随机选择5位翻转。
我正在尝试将此十六进制数据转换为二进制数据并使用位掩码方法来实现我的要求。然后将其转回十六进制。我很好奇有什么方法可以更快地完成这项工作吗?
抱歉,我的问题描述不够清楚。简而言之,我有一些十六进制数据,我想在这些数据中模拟位错误。例如,如果我有 5 个字节的十六进制数据:
"FF00FF00FF"
二进制表示是
"1111111100000000111111110000000011111111"
如果误码率为10%。然后我想让这 40 位有 4 位错误。一个极端的随机结果:前 4 位发生错误:
"0000111100000000111111110000000011111111"
【问题讨论】:
您能否详细说明“随机选择 5 位”是什么意思? 请向我们展示一些声明/定义 A char 数组的代码 可以多次翻转同一个位吗?请详细说明您的问题。 例如,如果我有一个 100 字节的十六进制数据。二进制表示中将有 100*8 位。我想让这些位中的随机 10% 为 0->1 或 1->0。 10% 是我的参数。和数组 A --> char A[]="0A F5 6D 02"; 不,一位最多只改变一次。 【参考方案1】:首先,找出bit代表的是哪个char:
参数是你要翻转的位...
char *byteToWrite = &A[sizeof(A) - (param / 8) - 1];
这将为您提供指向该数组偏移处的字符的指针(-1 表示 0 数组偏移与大小)
然后获取模数(如果您喜欢冒险,则可以进行更多位移)以找出此处要翻转的位:
*byteToWrite ^= (1u << param % 8);
因此,A[10]
处的字节的参数应为 5,以切换其第 5 位。
【讨论】:
我从右边开始读这个问题,而你从左边读它......这是可以理解的,因为在工作的二进制示例中设置了从任一端开始的第 5 位:00001010 11110101 01101101 00000010
vs 10001110 11110001 01101001 00100010
不管怎样,希望这对这个小伙子有很大帮助。
Sizeof(A) 总是会返回“4”。无论数组元素的数量是多少,这就是我要指出的。
问题说明 A 是一个数组 - 不是 char* - sizeof (char[11]) 将返回 11。
试试看 - sizeof (char*) 将返回本地指针的大小(通常在 32 位机器上为 4,在 64 位机器上为 8)。 sizeof(A) 其中 char[11] A = 0x01, .... 等;将返回 11。
是的,我意识到了,对不起。【参考方案2】:
-
将 2^n 的值存储在一个数组中
生成随机数种子
循环 x 次(在本例中为 5 次)并执行数据 ^= stored_values[random_num]
除了将 2^n 值存储在数组中之外,您还可以对 2 的随机幂进行一些位移,例如:
data ^= (1<<random%7)
反映第一条评论,你真的可以在你的函数中写出该行 5 次,并完全避免 for 循环的开销。
【讨论】:
如果你这样做就不需要循环 *(array + n),其中 n 是数组中的第 n 个字节(假设它是一个char
数组)【参考方案3】:
你有 32 位数字。您可以将这些位视为 hte 数字的一部分,然后将这个数字与一些随机的 5 位数字进行异或。
int count_1s(int )
int m = 0x55555555;
int r = (foo&m) + ((foo>>>1)&m);
m = 0x33333333;
r = (r&m) + ((r>>>2)&m);
m = 0x0F0F0F0F;
r = (r&m) + ((r>>>4)&m);
m = 0x00FF00FF;
r = (r&m) + ((r>>>8)&m);
m = 0x0000FFFF;
return r = (r&m) + ((r>>>16)&m);
void main()
char input[] = "0A F5 6D 02";
char data[4] = ;
scanf("%2x %2x %2x %2x", &data[0], &data[1], &data[2], &data[3]);
int *x = reinterpret_cast<int*>(data);
int y = rand();
while(count_1s(y) != 5)
y = rand(); // let's have this more random
*x ^= y;
printf("%2x %2x %2x %2x" data[0], data[1], data[2], data[3]);
return 0;
【讨论】:
【参考方案4】:我认为没有理由将整个字符串来回转换为十六进制表示法。只需从十六进制字符串中选择一个随机字符,将其转换为数字,稍微更改一下,再转换回十六进制字符。
在纯 C 中:
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
int main (void)
char *hexToDec_lookup = "0123456789ABCDEF";
char hexstr[] = "0A F5 6D 02";
/* 0. make sure we're fairly random */
srand(time(0));
/* 1. loop 5 times .. */
int i;
for (i=0; i<5; i++)
/* 2. pick a random hex digit
we know it's one out of 8, grouped per 2 */
int hexdigit = rand() & 7;
hexdigit += (hexdigit>>1);
/* 3. convert the digit to binary */
int hexvalue = hexstr[hexdigit] > '9' ? hexstr[hexdigit] - 'A'+10 : hexstr[hexdigit]-'0';
/* 4. flip a random bit */
hexvalue ^= 1 << (rand() & 3);
/* 5. write it back into position */
hexstr[hexdigit] = hexToDec_lookup[hexvalue];
printf ("[%s]\n", hexstr);
return 0;
它可能甚至可以省略convert-to-and-from-ASCII步骤——在字符串中翻转一点,检查它是否仍然是一个有效的十六进制数字,然后如有必要,进行调整。
【讨论】:
【参考方案5】:首先随机选择x个位置(每个位置由数组索引和位位置组成)。
现在,如果您想从右侧翻转第 ith 位以获得数字 n。通过 2n 找到 n
的其余部分:
代码:
int divisor = (2,i);
int remainder = n % divisor;
int quotient = n / divisor;
remainder = (remainder == 0) ? 1 : 0; // flip the remainder or the i th bit from right.
n = divisor * quotient + remainder;
【讨论】:
【参考方案6】:取输入的 mod 8(5%8)
将0x80
右移输入值(例如 5)
将此值与字符数组的第 (input/8) 个元素进行异或。
代码:
void flip_bit(int bit)
Array[bit/8] ^= (0x80>>(bit%8));
【讨论】:
什么是 Ex-OR?只听说过 XOR 或 Exclusive OR :) C 中 Ex-OR 的运算符是 "^" (a^b)。 哦,我称之为 Ex-OR(异或)对不起。以上是关于如何在 C/C++ 中随机翻转 char 的二进制位的主要内容,如果未能解决你的问题,请参考以下文章
将带有随机 char 元素的 char[] 转换为一个 int