将二进制文件从一个位置转换为字符串到另一个位置

Posted

技术标签:

【中文标题】将二进制文件从一个位置转换为字符串到另一个位置【英文标题】:Converting binary to string from one location to other 【发布时间】:2021-04-08 21:00:44 【问题描述】:

我正在尝试将数据从二进制形式转换为字符串资源, 到目前为止,我得到了这段代码,但它不能正常工作,有任何建议吗? 代码是c/c++

char* binaryToString(char* b) 
    int length = strlen(b);
    char* result = (char*)malloc(length / 8);
    for (int i = 0; i < length; i++, b += 8) 
        result[i] = strtol(b, NULL, 2);
    
    return result;

【问题讨论】:

请解释每一行代码背后的想法。输入是什么?实际输出是多少?您期望的输出是什么? 您问的是 C 还是 C++?它们不是同一种语言,答案可能不同。 【参考方案1】:

您分配了一个 length/8 元素数组,但您在索引 0 到 length - 1 处写入 => 您从分配的数组中写入,行为未定义

替换

char* result = (char*)malloc(length / 8);

通过

char* result = malloc(length);

或者当然改变你的循环

目前您也很可能会从 b 管理的数组中读出,因为您每次进步 8 个字符,所以您从索引 0 调用 strtol,然后是 8 ...然后8*(length-1),将数组读取为未定义行为

其他问题

您将charlong 分配给您的数组,您真的要这样做吗? strtol 肯定不会像你在输入字符串中那样产生你期望的值

根据您的评论,一种方法是:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char* binaryToString(char * b)

  size_t n = (strlen(b) + 7) / 8;
  char * result = malloc(n + 1);
  size_t i;
  
  for (i = 0; i < n; i++, b += 8) 
    char s[9];
    
    strncpy(s, b, 8);
    s[8] = 0;
    result[i] = (char) strtol(s, NULL, 2);
  
  result[i] = 0;
  
  return result;


int main(int argc, char ** argv)

  while (--argc) 
    argv += 1;
    
    char * r = binaryToString(*argv);
    
    printf("%s -> %s\n", *argv, r);
    free(r);
  
  
  return 0;

我使用缓冲区复制每个最多 8 个字符的块,以不修改输入字符串。

警告:

假设 char 可以支持从 0 到 255 的值(请参阅 CHAR_BIT) 即使 strtol 允许这样做,也不会检查输入字符串的有效性。 如果输入字符串的长度不是 8 的倍数但大于 8,即使没有未定义的行为,结果也不是预期的。 结果可以包含不可读的字符,包括在分配数组的最后位置放置的空字符之前的空字符。

编译和执行:

pi@raspberrypi:/tmp $ gcc -Wall -g cv.c 
pi@raspberrypi:/tmp $ 
pi@raspberrypi:/tmp $ ./a.out 01100001011100110110010001100110 100001 0110000100000000011100110110010001100110
01100001011100110110010001100110 -> asdf
100001 -> !
0110000100000000011100110110010001100110 -> a
pi@raspberrypi:/tmp $ 
pi@raspberrypi:/tmp $ valgrind ./a.out 01100001011100110110010001100110 100001 0110000100000000011100110110010001100110
==12327== Memcheck, a memory error detector
==12327== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==12327== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==12327== Command: ./a.out 01100001011100110110010001100110 100001 0110000100000000011100110110010001100110
==12327== 
01100001011100110110010001100110 -> asdf
100001 -> !
0110000100000000011100110110010001100110 -> a
==12327== 
==12327== HEAP SUMMARY:
==12327==     in use at exit: 0 bytes in 0 blocks
==12327==   total heap usage: 4 allocs, 4 frees, 1,037 bytes allocated
==12327== 
==12327== All heap blocks were freed -- no leaks are possible
==12327== 
==12327== For lists of detected and suppressed errors, rerun with: -s
==12327== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
pi@raspberrypi:/tmp $ 

(在 0110000100000000011100110110010001100110 的情况下,结果的第二个字符是空字符,因此不会打印下一个字符)

【讨论】:

如果它得到 01010101 它的 strlen 将是 8?我需要 1 result 需要是未来字符串的长度,它需要比二进制 'string' 小 8 倍 @NikolaNikolic 索引必须介于 0 和元素数减一之间 @NikolaNikolic 你的目标是什么?获取一个表示二进制数的字符串并生成一个与基数为 256 的相同数字对应的数组? strtol 没有按照您的设想进行,因为它适用于从 b 然后 b+8 等的所有字符串【参考方案2】:

strtol 将输入字符串解释为一个整数,因为每个 8 字符组之间没有空格。所以,我为你提出了一个简单的解决方法,将每组字符复制到一个缓冲区中,并在缓冲区的末尾附加一个 '\0'。

另外,我修复了长度计算错误。

char* binaryToString(char* b) 
    int length = (strlen(b)+7)/8 + 1;
    char buf[9];
    buf[8] = '\0';
    char* result = (char*)malloc(length);
    for (int i = 0; i < length; i++, b += 8) 
        strncpy(buf, b, 8);
        result[i] = strtol(buf, NULL, 2);
    
    result[length - 1] = '\0';
    return result;

【讨论】:

为什么要在长度上加上+1?我认为代码运行良好,只需删除 +1 并将 null 更改为 result[length]【参考方案3】:

strtol 将使用尽可能多的字符来转换为整数值。它不知道您只想转换接下来的 8 个二进制数字。您可以自己进行转换,而不是尝试解决该行为。例如:

char *binaryToString(const char *b)

    int length = strlen(b) / 8;
    char *result = malloc(length + 1);
    if (result) 
        for (int i = 0; i < length; ++i) 
            // convert 8 binary digits to integer value
            int value = 0;
            for (int j = 0; j < 8; ++j) 
                value = (value << 1) + *b++ - '0';
            
            result[i] = value;
        
        result[length] = '\0'; // string must be null terminated
    
    return result;

请注意,这不会像 strtol 那样进行错误检查。

【讨论】:

以上是关于将二进制文件从一个位置转换为字符串到另一个位置的主要内容,如果未能解决你的问题,请参考以下文章

尝试用二进制值填充数组并确定最低有效位

8.数值进制运算与字符编码转换

如何将数值转化为二进制数?

为啥我的二进制到十进制转换器程序中只有前 2 个输出正确?

将二进制数据移动到一个文件中的特定值到另一个文件中

将文件夹结构(不含文件)从一个位置复制到另一个位置