gpt4 book ai didi

从 uint32/16_t 创建一个字符串,然后解析回原始数字

转载 作者:太空宇宙 更新时间:2023-11-04 07:33:13 30 4
gpt4 key购买 nike

我需要将一些 uint32_t 和 uint16_t 数字放入 char* 中。然后我需要从缓冲区中取回它们。

我已经阅读了一些问题,并尝试使用 sprintf 将它们放入 char* 中,然后 sscanf 再次获取原始数字。但是,我无法正确获取它们。

这是我的代码示例,只有 2 个数字。但我需要超过 2 个,这就是我使用 realloc 的原因。另外,我不知道如何通过 uint16_t 正确使用 sprintf 和 sscanf

uint32_t gid = 1100;
uint32_t uid = 1000;
char* buffer = NULL;
uint32_t offset = 0;

buffer = realloc(buffer, sizeof(uint32_t));
sprintf(buffer, "%d", gid);
offset += sizeof(uint32_t);

buffer = realloc(buffer, sizeof(uint32_t) + sizeof(buffer));
sprintf(buffer+sizeof(uint32_t), "%d", uid);

uint32_t valorGID;
uint32_t valorUID;

sscanf(buffer, "%d", &valorGID);
buffer += sizeof(uint32_t);
sscanf(buffer, "%d", &valorUID);

printf("ValorGID %d ValorUID %d \n", valorGID, valorUID);

我得到的是

ValorGID 11001000 ValorUID 1000 

我需要得到的是

ValorGID 1100 ValorUID 1000

我是 C 的新手,所以任何帮助将不胜感激。

最佳答案

buffer = realloc(buffer, sizeof(uint32_t));
sprintf(buffer, "%d", gid);
offset += sizeof(uint32_t);

buffer = realloc(buffer, sizeof(uint32_t) + sizeof(buffer));
sprintf(buffer+sizeof(uint32_t), "%d", uid);

这真的没有意义,除非在幸运的情况下,否则不会按预期工作。

让我们假设通常的 CHAR_BIT == 8成立,所以 sizeof(uint32_t) == 4 .此外,让我们假设 int是一个带符号的 32 位整数,采用二进制补码表示,没有填充位。

sprintf(buffer, "%d", gid)打印 gid 的位模式的十进制字符串表示形式解释为 int缓冲。在上述假设下,gid被解释为介于 -2147483648 和 2147483647 之间的数字。因此,十进制字符串表示可能包含 '-' , 包含 1 到 10 个数字和 0 终止符,总共使用 2 到 12 个字节。但是你只分配了四个字节,所以每当999 < gid < 2^32-99 (带符号的二进制补码解释为 > 999< -99 ),sprintf写入超过分配的缓冲区大小。

这是未定义的行为。

它可能不会立即崩溃,因为分配四个字节通常会有效地为您提供更大的内存块(例如 malloc 总是返回 16 字节对齐的 block ,分配的四个字节后面的十二个字节不能被其他部分使用的程序,但属于程序的地址空间,并且写入它们可能不会被发现)。但是当分配的 block 的末尾位于页面边界时,它很容易在以后崩溃。

此外,由于您将后续的 sprintf 的写入偏移量提前了四个字节s,如果字符串表示(不包括 0 终止符)使用超过四个字节(同时程序还没有因写入未分配的内存而崩溃),则前一个数字的一​​部分将被覆盖。

线

buffer = realloc(buffer, sizeof(uint32_t) + sizeof(buffer));

包含更多错误。

  1. buffer = realloc(buffer, new_size);如果 realloc,则丢失对已分配内存的引用并导致泄漏失败。使用临时文件并检查是否成功

    char *temp = realloc(buffer, new_size);
    if (temp == NULL) {
    /* reallocation failed, recover or cleanup */
    free(buffer);
    exit(EXIT_FAILURE);
    }
    /* it worked */
    buffer = temp;
    /* temp = NULL; or let temp go out of scope */
  2. 新尺寸sizeof(uint32_t) + sizeof(buffer)新分配的数量始终相同,sizeof(uint32_t) + sizeof(char*) .这通常是 8 或 12 个字节,因此在分配的区域之外写入并导致崩溃或内存损坏(这可能会在很久以后导致崩溃)不需要很多数字。

必须跟踪分配给buffer 的字节数并用它来计算新的尺寸。没有(可移植的)方法来确定从指针到其开始的已分配内存块的大小。


现在的问题是您是想在缓冲区中存储字符串表示形式还是位模式。

存储字符串表示存在字符串表示的长度随值变化的问题。因此,您需要在数字表示之间包含分隔符,或者在必要时通过填充(使用空格或前导零)确保所有表示具有相同的长度。例如,这将像

#include <stdint.h>
#include <inttypes.h>

#define MAKESTR(x) # x
#define STR(x) MAKESTR(x)

/* A uint32_t can use 10 decimal digits, so let each field be 10 chars wide */
#define FIELD_WIDTH 10

uint32_t gid = 1100;
uint32_t uid = 1000;

size_t buf_size = 0, offset = 0;
char *buffer = NULL, *temp = NULL;
buffer = realloc(buffer, FIELD_WIDTH + 1); /* one for the '\0' */
if (buffer == NULL) {
exit(EXIT_FAILURE);
}
buf_size = FIELD_WIDTH + 1;
sprintf(buffer, "%0" STR(FIELD_WIDTH) PRIu32, gid);
offset += FIELD_WIDTH;

temp = realloc(buffer, buf_size + FIELD_WIDTH);
if (temp == NULL) {
free(buffer);
exit(EXIT_FAILURE);
}
buffer = temp;
temp = NULL;
buf_size += FIELD_WIDTH;
sprintf(buffer + offset, "%0" STR(FIELD_WIDTH) PRIu32, uid);
offset += FIELD_WIDTH;
/* more */

uint32_t valorGID;
uint32_t valorUID;

/* rewind for scanning */
offset = 0;

sscanf(buffer + offset, "%" STR(FIELD_WIDTH) SCNu32, &valorGID);
offset += FIELD_WIDTH;
sscanf(buffer + offset, "%" STR(FIELD_WIDTH) SCNu32, &valorUID);

printf("ValorGID %u ValorUID %u \n", valorGID, valorUID);

具有零填充的固定宽度字段。如果您更愿意使用分隔符而不是固定宽度,则所需长度和偏移量的计算会变得更加复杂,但除非数字很大,否则它会使用更少的空间。

如果您更愿意存储位模式,这将是最紧凑的存储方式,您可以使用类似

size_t buf_size = 0, offset = 0;
unsigned char *buffer = NULL, temp = NULL;
buffer = realloc(buffer, sizeof(uint32_t));
if (buffer == NULL) {
exit(EXIT_FAILURE);
}
buf_size = sizeof(uint32_t);
for(size_t b = 0; b < sizeof(uint32_t); ++b) {
buffer[offset + b] = (gid >> b*8) & 0xFF;
}
offset += sizeof(uint32_t);

temp = realloc(buffer, buf_size + sizeof(uint32_t));
if (temp == NULL) {
free(buffer);
exit(EXIT_FAILURE);
}
buffer = temp;
temp = NULL;
buf_size += sizeof(uint32_t);
for(size_t b = 0; b < sizeof(uint32_t); ++b) {
buffer[offset + b] = (uid >> b*8) & 0xFF;
}
offset += sizeof(uint32_t);

/* And for reading the values */
uint32_t valorGID, valorUID;

/* rewind */
offset = 0;
valorGID = 0;
for(size_t b = 0; b < sizeof(uint32_t); ++b) {
valorGID |= buffer[offset + b] << b*8;
}
offset += sizeof(uint32_t);
valorUID = 0;
for(size_t b = 0; b < sizeof(uint32_t); ++b) {
valorUID |= buffer[offset + b] << b*8;
}
offset += sizeof(uint32_t);

¹ 如果你知道怎么做 malloc等在您的实现中工作,可能会从 malloc 中找到大小的簿记数据。

关于从 uint32/16_t 创建一个字符串,然后解析回原始数字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11425817/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com