【问题标题】:memcpy boolean to void *memcpy 布尔值无效 *
【发布时间】:2020-10-26 13:17:14
【问题描述】:

我只是在创建一个测试函数,我必须在 void * 中传递布尔值,以便我可以在其他函数中解析它并使用它。

但我被卡住了,不知道我应该如何在 void * 中存储布尔值。

但是当我在另一个函数中解析它时,我总是得到真值。

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

typedef struct {
    int a;
    uint8_t var_data[];
} s;

void parse(s * dummy)
{
    void *var_data = dummy->var_data;
    
    uint8_t *len;
    char type[128];
    bool *leaf;
    for(int i = 0; i < dummy->a; i++)
    {
        len = (uint8_t *)var_data;
        var_data += 1;
        memcpy(type, var_data, *len);
        type[*len] = '\0';
        var_data += *len;
        leaf = (bool *)var_data;
        var_data += 1;
        
        printf("%s\n", type);
        printf("leaf: %s\n\n", leaf ? "true" : "false");
    }
}

int main() 
{
    // Write C code here
    char val[] = "dummy value";
    uint8_t len = strlen(val);
    bool v = false;
    int b = 2;
    int sz = sizeof(s) + b * (sizeof(bool) + len + 1);
    s * dummy = (s *) malloc(sz);
    dummy->a = b;
    void *var = dummy->var_data;
    for(int i = 0; i < dummy->a; i++){
        memcpy(var, &len, 1);
        var += 1;
        memcpy(var, val, len);
        var += len;
        memcpy(var, &v, sizeof(bool));
        var += sizeof(bool);
    }
    parse(dummy);
    return 0;
}

body 可以帮我解决这个问题吗?

【问题讨论】:

  • 你有一个指针var_data,但是它指向哪里?
  • 到一些结构的变量数据。
  • 另外,你在memcpy 调用之后增加了var_data,这意味着它不再指向你复制到它所指向的数据。所以“在另一个函数中”,指针并没有指向你认为的数据。
  • 请edit 您的问题包含正确的minimal reproducible example。也请尝试解释为什么你需要这样做。您要解决的原始问题是什么。
  • A minimal reproducible example 不应该是您的“完整代码”,它应该足以让我们复制粘贴并复制您提出的问题,仅此而已。

标签: c boolean memcpy void-pointers


【解决方案1】:

var_data 未初始化。你应该用malloc分配var_data,并将leaf中的数据复制进去:

void *var_data = malloc(sizeof(bool));
bool leaf = false;
memcpy(var_data, &leaf, sizeof(bool));

您可以像这样将其转换为bool *:

bool *leaf;
leaf = (bool *) var_data;

此外,您增加var_data 指针。所以var_data 现在指向不同的内存位置。

【讨论】:

  • 先生,我刚刚没有在此处添加 malloc peice 代码,但我做了同样的事情,即使我通过了 false 值,它也显示为 true。
  • @SaranshDixit:如果你不发布你的实际代码,人们只能猜测问题出在哪里。
  • 对不起@Groo先生,我已经添加了我面临的问题的虚拟代码
【解决方案2】:

您没有在此行中取消引用 leaf:

printf("leaf: %s\n\n", leaf ? "true" : "false");

由于leaf 是一个非零指针,它在C 中的计算结果始终为true。您想打印*leaf:

printf("leaf: %s\n\n", *leaf ? "true" : "false");

其他一些杂记:

  1. void* 算术(即var_data += 1)在 C 中是非法的,尽管 gcc 不会抱怨。使用char*,因为这是应该用于序列化的类型。

  2. 正如其他答案中所提到的,像您现在这样使用指针可能会导致细微的错误。如果您的指针指向一个地址并且您想取消引用它(读取存储在那里的值),最好尽快执行此操作,而不是冒着同时该位置被其他代码更改的风险。

    所以,只需将 char* 数组中的数据复制到目标结构(或 uint8_t 之类的原语)中,然后将指针前进。

  3. 技术上允许您在 C 中转换指针的唯一方法是将它们从特定指针(如something*)转换为char*,以便检查它们的内容。您也可以隐式地从void* 转换为void*,但前提是您没有为指针设置别名(试图修改基础类型)。其他方向的任何强制转换都违反了严格的别名,因此您应该尝试改用memcpy。它可能看起来更丑陋,但编译器无论如何都会对其进行优化(see for yourself),并且您将安全(r)从the horrors of aliasing。

  4. 让它尽可能地尝试使用 const 正确性是一个好习惯,它有助于编译器在你做错了什么时警告你。如果您的函数正在解析数组,则参数应为const char*。

  5. 最后,如果您的目标是序列化和反序列化结构,也许您应该研究protocol buffers 或一些类似的序列化框架。它快速、高效、便携,而且最重要的是,它已经编写好了。

所以,类似:

typedef struct {
    int len;  
    char * var_data;
} example;

// note the const keyword - this means this function is
// not going to change the struct, only read it
void parse(const example * dummy)
{
    // again, pointer to const char
    const char * var_data = dummy->var_data;
    
    // move all variables to the innermost scope
    for (int i = 0; i < dummy->len; i++)
    {
        uint8_t len = 0;
        memcpy(&len, var_data, sizeof(len));
        var_data++;

        ...
    }
}

【讨论】:

  • 好的,现在我明白了,我犯了一个错误,我会尽力记住您所说的所有要点,先生。感谢您的指导。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-11
  • 1970-01-01
  • 2017-01-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多