【问题标题】:Divide char* into few variables将 char* 分成几个变量
【发布时间】:2016-11-21 22:44:53
【问题描述】:

我有一些字符数组:char char[8] 其中包含例如两个整数,前 4 个索引是第一个整数,接下来的 4 个索引是第二个整数。

char array[8] = {0,0,0,1,0,0,0,1};
int a = array[0-3]; // =1;  
int b = array[4-8]; // =1;

如何将此数组转换为两个 int?

可以有任何其他类型,不一定是int,但这只是一些例子:

我知道我可以将此数组复制到两个大小为 4 的 char 数组,然后将每个数组转换为 int。但是我觉得这样不好,而且违反了干净代码的原则。

【问题讨论】:

  • 我无法理解您为什么要这样做,但memcpy 可能会帮助您...
  • 由于字节序,您不能只将char* 转换为int*
  • 看起来你想要一些魔法发生。不幸的是,这个世界上没有魔法。您必须编写一个函数来进行转换。
  • @c650: 我有 char 数组,里面有一些变量,现在我想把它“解码”成具有良好类型的变量:int、longlong、double。
  • aarray[8] = {1,2,3,4,0,0,0,1}; 有什么价值?是1234吗?

标签: c++ c arrays


【解决方案1】:

如果您的数据具有正确的字节顺序,您可以使用 memcpy 从字节缓冲区中提取可寻址类型:

int8_t array[8] = {0,0,0,1,0,0,0,1};
int32_t a, b;
memcpy(&a, array + 0, sizeof a);
memcpy(&b, array + 4, sizeof b);

虽然@Vivek 是正确的,ntohl 可用于规范化字节顺序,但您必须将其作为第二步。不要玩带有指针的游戏,因为这违反了strict aliasing 并导致未定义的行为(实际上,对齐异常或优化器将大部分代码丢弃为不可访问)。

int8_t array[8] = {0,0,0,1,0,0,0,1};
int32_t tmp;
memcpy(&tmp, array + 0, sizeof tmp);
int a = ntohl(tmp);
memcpy(&tmp, array + 4, sizeof tmp);
int b = ntohl(tmp);

请注意,几乎所有优化编译器都足够聪明,不会在看到memcpy 带有一个小的常量计数参数时调用函数。

【讨论】:

    【解决方案2】:

    让我们使用一点C++算法,比如std::accumulate

    #include <numeric>
    #include <iostream>
    
    int getTotal(const char* value, int start, int end)     
    {
        return std::accumulate(value + start, value + end, 0, 
                               [](int n, char ch){ return n * 10 + (ch-'0');});
    }
    
    int main()
    {
        char value[8] = {'1','2','3','4','0','0','1','4'};
        int total1 = getTotal(value, 0, 4);
        int total2 = getTotal(value, 4, 8);
        std::cout << total1 << " " << total2;
    }
    

    注意std::accumulate 和 lambda 函数的用法。我们所做的只是得到一个运行总计,将每个小计乘以 10。字符通过简单地减去 '0' 转换为一个数字。

    Live Example

    【讨论】:

    • 如果char[] 包含具有固定宽度十进制数字的ASCII 文本,那么这将是一个好方法。我将这个问题解释为二进制数据不是文本,但实际上并没有说这可能是正确的。
    • ^ 相同。我认为它应该更像是一个演员而不是atoi
    【解决方案3】:

    您可以将数组中的字节类型强制转换为int *。然后取消引用将导致 4 个字节被读取为 int。然后做一个 ntohl,将确保 int 中的字节按照主机顺序排列。

    char array[8] = {0,0,0,1,0,0,0,1};
    
    int a = *((int *)array);  
    int b = *((int *)&array[4]);
    
    a = ntohl(a);  
    b = ntohl(b);
    

    这将在小端和大端系统上将 a 和 b 设置为 1。

    如果编译器设置了严格别名,可以使用memcpy来实现,如下:

    char array[8] = {0,0,0,1,0,0,0,1};
    int a, b;
    
    memcpy(&a, array, sizeof(int));
    memcpy(&b, array+4, sizeof(int));
    
    a = ntohl(a);  
    b = ntohl(b);  
    

    【讨论】:

    • 这是未定义的行为。严格的别名允许您使用char* 访问int,它不允许您使用int* 访问char[]。坏事接踵而至。
    • 它适用于小端系统。我只是尝试过仔细检查。也可以使用 memcpy。
    猜你喜欢
    • 2020-12-20
    • 1970-01-01
    • 2022-08-13
    • 1970-01-01
    • 2018-02-28
    • 1970-01-01
    • 1970-01-01
    • 2014-09-11
    • 1970-01-01
    相关资源
    最近更新 更多