c - 将十六进制转换为二进制字符串,打印为垃圾符号
问题描述
我正在尝试将十六进制字符串转换为二进制,稍后将传递给加密库(openssl AES EVP_xx),所以我想我只需要一个带有 nul 终止符的二进制字符串。
我使用了Josch演示的第二个测试, 他的测试用例非常强大,所以我最终使用了查找表。我只是更改了输入变量并添加了打印,但总是打印垃圾。
我只添加了以下内容:
malloc(预期的二进制字符串长度 + 1)
在循环结束时设置 nul 终止符。AFAIK 这些垃圾字符在字符串不为空终止时返回。
#include <string.h> #include <stdio.h> #include <stdlib.h> /* the resulting binary string is half the size of the input hex string * because every two hex characters map to one byte */ unsigned char base16_decoding_table1[256] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}; int main(int argc, char **argv){ int TESTDATALEN=strlen(( char*) argv[1]); //char *result=malloc((TESTDATALEN/2)+1); int mallocLen=(TESTDATALEN%2) ? ((TESTDATALEN+3)/2) : ((TESTDATALEN/2)+1); unsigned char *result=malloc(mallocLen); *result='\0'; int i; unsigned char cur; unsigned char val; for (i = 0; i < TESTDATALEN; i++) { cur = argv[1][i]; val = base16_decoding_table1[(int)cur]; /* even characters are the first half, odd characters the second half * of the current output byte */ if (i%2 == 0) { result[i/2] = val << 4; } else { result[i/2] |= val; } } result[mallocLen] = '\0'; printf ("Binary value: %s\n", result); //for (i = 0; i < TESTDATALEN/2; i++) printf ("%02hhx", result[i]); //putchar ('\n'); free(result); return 0; }
如果相关,我可能会在上下文中添加更多内容;由于性能原因,我无法触摸 strcat,因为十六进制到二进制只是加密中的一个步骤,它是在数千(或数百万)个输入上执行的,单个字段可以达到 8kb,因此也不能使用 strtol 并且必须这样做它在字符串中,
当前输出为:
hex2bin1.6.2 abc123def789
��#�</p>
虽然此值的二进制等效值为:101010111100000100100011110111101111011110001001
目标是将此转换代码返回的二进制字符串提供给 openssl AES EVP 加密例程,该例程接受并返回二进制输入。
提前致谢
解决方案
好吧。让我们理清头绪。您最大的误解是 的内容result
将是可使用puts()
或printf()
使用"%s"
转换说明符打印的字符串。结果中的值不是 ASCII 值,它们是查找上的整数值base16_decoding_table1[]
。它不包含 ASCII 字符值。如果它确实包含字符值,则初始化程序中的每个元素都将用单引号括起来,例如'0','0','0',...
,索引的条目 65-70
将是'A','B','C','D','E','F',...
See ASCII Table & Description。
如评论中所述,所有数字都以二进制形式存储在内存中。当您查看integer
具有十进制值、八进制值或十六进制值的值时,这些都只是内存中相同二进制位的不同视图。如果您想查看实际的二进制位,您只需要直接从内存中输出该位的表示。
有很多方法可以做到这一点,但是可以通过以下方式完成 s 的简单未填充二进制输出'0'
并'1'
对应于内存中的二进制0
s 和s:1
/** unpadded binary representation of 'v'. */
void binprn (const unsigned long v)
{
if (!v) { putchar ('0'); return; };
size_t sz = sizeof v * CHAR_BIT;
unsigned long rem = 0;
while (sz--)
if ((rem = v >> sz))
putchar ((rem & 1) ? '1' : '0');
}
现在您只需将hex
输入作为程序参数,将其转换为存储值,然后输出该数字的二进制表示。由于您正在处理无符号数字,因此该strtoul()
函数是一种简单的方法来获取十六进制字符输入并将其转换为内存中存储的无符号值。您在下面的更新代码中指出了这一点:
(编辑:TESTDATALEN
如果为奇数或设置结果大小1
,并且注意大小结果每字节包含 2 个字符,奇数的输出字节TESTDATALEN
将被零填充。)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h> /* for errno for strtoul validation */
#include <limits.h> /* for CHAR_BIT */
/* the resulting binary string is half the size of the input hex string
* because every two hex characters map to one byte */
unsigned char base16_decoding_table1[256] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,10,11,12,13,14,15,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
/** unpadded binary representation of 'v'. */
void binprn (const unsigned long v)
{
if (!v) { putchar ('0'); return; };
size_t sz = sizeof v * CHAR_BIT;
unsigned long rem = 0;
while (sz--)
if ((rem = v >> sz))
putchar ((rem & 1) ? '1' : '0');
}
int main(int argc, char **argv){
if (argc < 2) /* validate 1 argument given */
return 1;
size_t TESTDATALEN = strlen(argv[1]),
resultsz = TESTDATALEN / 2 + TESTDATALEN % 2; /* must have 1 char */
unsigned char *result = calloc (resultsz, 1); /* initialize result all 0 */
errno = 0; /* zero errno before call to strtoul */
char *endptr; /* end-pointer for strtoul validation */
size_t i;
int cur;
unsigned char val;
unsigned long value = strtoul (argv[1], &endptr, 16); /* convert input */
if (endptr == argv[1]) { /* check if no digits converted */
fputs ("error: invalid hex format - no digits converted.\n", stderr);
return 1;
}
else if (errno) { /* check for under/overflow */
fputs ("error: overflow in conversion to hex.\n", stderr);
return 1;
}
for (i = 0; i < TESTDATALEN; i++) {
cur = argv[1][i];
val = base16_decoding_table1[cur];
/* even characters are the first half, odd characters the second half
* of the current output byte */
if (i % 2 == 0)
result[i/2] = val << 4;
else
result[i/2] |= val;
}
printf ("hex value: %lx\nresult : ", value); /* output stored value */
for (i = 0; i < resultsz; i++) /* output bytes in result */
printf ("%02hhx", result[i]);
putchar ('\n');
fputs ("binary : ", stdout); /* output binary of value */
binprn (value);
putchar ('\n');
free(result);
}
示例使用/输出
现在,当您为有效的十六进制数字提供字符表示时,您将获得存储value
输出的十六进制表示,然后是存储在 中的字节result
,然后是存储在中value
和以字节形式存储在中的二进制表示result
,例如
$ ./bin/base16decode aaff
hex value: aaff
result : aaff
binary : 1010101011111111
如果您还有其他问题,请仔细查看并告诉我。
推荐阅读
- python - Django Modals,从列中删除非数字字符,CAST 为整数,然后按顺序排序
- python - 如何从列表中删除特定值
- python - 我正在尝试制作一个丢失的号码查找器。这是我的代码和我得到的错误
- azure-devops - Azure DevOps 错误 401 帐户无权查看此页面
- windows - SignTool 错误:未找到符合所有给定条件的证书。VS2019
- ssh - 端口转发以避免需要证书
- php - 仅返回查询中的字段
- javascript - 来自 API 的重复响应
- python - 如何制作一个过滤脏话的不和谐机器人
- flutter - 'showSnackBar' 已弃用,不应使用