memcpy 布尔值到 void *
memcpy boolean to void *
我刚刚创建了一个测试函数,其中我必须在 void * 中传递布尔值,以便我可以在其他函数中解析它并使用它。
但我被卡住了,不知道我应该如何在 void * 中存储布尔值。
但是当我在另一个函数中解析它时,我总是得到 true 的值。
#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] = '[=10=]';
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
未初始化。你应该用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
现在指向不同的内存位置。
您没有在这一行取消引用 leaf
:
printf("leaf: %s\n\n", leaf ? "true" : "false");
因为 leaf
是一个 non-zero 指针,它在 C 中总是求值为 true
。你想打印 *leaf
代替:
printf("leaf: %s\n\n", *leaf ? "true" : "false");
其他一些杂项备注:
void*
算术(即 var_data += 1
)在 C 中是非法的,尽管 gcc 不会抱怨。使用 char*
因为这是应该用于序列化的类型。
如其他答案中所述,像您现在这样使用指针可能会导致细微的错误。如果您的指针指向一个地址并且您想取消引用它(读取存储在那里的值),最好尽快这样做,而不是冒着这个位置同时被其他代码更改的风险。
因此,只需将 char*
数组中的数据复制到目标结构(或像 uint8_t
这样的基元),然后推进指针。
技术上允许在 C 中转换指针的唯一方法是将它们从一个特定的指针(如something*
)转换为char*
,以便检查其内容。您也可以从 void*
隐式转换到 void*
,但前提是您没有为指针设置别名(尝试修改基础类型)。任何其他方向的转换都违反了严格的别名,因此您应该尝试使用 memcpy
代替。它可能看起来更丑陋,但无论如何编译器都会对其进行优化 (see for yourself) and you'll be safe(r) from the horrors of aliasing.
一个很好的习惯是尽可能使用 const-correctness,它可以帮助编译器在您做错事情时发出警告。如果你的函数是解析数组,参数应该是const char*
.
最后,如果您的目标是序列化和反序列化结构,也许您应该研究一下 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++;
...
}
}
我刚刚创建了一个测试函数,其中我必须在 void * 中传递布尔值,以便我可以在其他函数中解析它并使用它。
但我被卡住了,不知道我应该如何在 void * 中存储布尔值。
但是当我在另一个函数中解析它时,我总是得到 true 的值。
#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] = '[=10=]';
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
未初始化。你应该用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
现在指向不同的内存位置。
您没有在这一行取消引用 leaf
:
printf("leaf: %s\n\n", leaf ? "true" : "false");
因为 leaf
是一个 non-zero 指针,它在 C 中总是求值为 true
。你想打印 *leaf
代替:
printf("leaf: %s\n\n", *leaf ? "true" : "false");
其他一些杂项备注:
void*
算术(即var_data += 1
)在 C 中是非法的,尽管 gcc 不会抱怨。使用char*
因为这是应该用于序列化的类型。如其他答案中所述,像您现在这样使用指针可能会导致细微的错误。如果您的指针指向一个地址并且您想取消引用它(读取存储在那里的值),最好尽快这样做,而不是冒着这个位置同时被其他代码更改的风险。
因此,只需将
char*
数组中的数据复制到目标结构(或像uint8_t
这样的基元),然后推进指针。技术上允许在 C 中转换指针的唯一方法是将它们从一个特定的指针(如
something*
)转换为char*
,以便检查其内容。您也可以从void*
隐式转换到void*
,但前提是您没有为指针设置别名(尝试修改基础类型)。任何其他方向的转换都违反了严格的别名,因此您应该尝试使用memcpy
代替。它可能看起来更丑陋,但无论如何编译器都会对其进行优化 (see for yourself) and you'll be safe(r) from the horrors of aliasing.一个很好的习惯是尽可能使用 const-correctness,它可以帮助编译器在您做错事情时发出警告。如果你的函数是解析数组,参数应该是
const char*
.最后,如果您的目标是序列化和反序列化结构,也许您应该研究一下 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++;
...
}
}