【问题标题】:C++ access to specific address in void*C++ 访问 void* 中的特定地址
【发布时间】:2014-07-14 02:18:49
【问题描述】:

您好,感谢您的帮助!

我正在尝试为多种数据类型(char、int、float、...等等)制作通用数据缓冲区,我想知道如何使用指向缓冲区的指针和特定位置访问特定地址。

让我举例说明:

1.) 假设我想保存到缓冲区 4 个变量(int、int、char、float)

2.) 所以,这个缓冲区的大小是:int size = sizeof(int)*2 + sizeof(char) + sizeof(float)

3.) 所以,缓冲区:void* buffer = malloc(size);

4.) 现在,我已经分配了缓冲区,我想将一些浮点变量写入特定位置 - 缓冲区 + (sizeof(int)*2 + sizeof(char) ) 对吗?如何做到这一点,如果有可能......

我有解决方案,我将写入数据如何指定它们及其工作,但我想跳到任何位置(当然,当我知道时,某个变量在缓冲区中的确切位置(地址))

所以类似的东西对我有用:

int* val1 = (int*) buffer;
*val1 = 1;
buffer = val1+1; //move pointer behind first position (+ sizeof(int))
int* val2 = (int*) buffer;
*val2 = 2;
buffer = val2+1; //move pointer behind second position (+ sizeof(int))
char* val3 = (char*) buffer;
*val3 = 'a';
buffer = val+1; //move pointer behind third position (+ sizeof(char))
float* val4 = (float*) buffer;
*val4 = 11.4;

--> 所有数据都正确保存在缓冲区中

但我更有趣的是,如果可能(以及如何)在第 4 个位置跳转并写入第一个浮点数(不要忘记之前是 int、int、char)

因为我不能使用类似的东西:

float* val4 = (float*) buffer + 4; // value 4 has address buffer + sizeof(float)*4 and I need     address buffer + sizeof(int)*2 + sizeof(char)

抱歉,这个解释太慢了,但我想确定一下,我需要解决的问题真的很明显。非常感谢您的帮助!

ps:我脑子里只有一个带有 (char*) 缓冲区的解决方案(因为在每个平台上都应该是 sizeof(char) == 1 ....但我不确定,如果这真的是保存选项)

之后:

char* pointerOnVal4 = (char*) buffer + sizeof(int)*2 + sizeof(char);
float* val4 = (float*) pointerOnFloat;`

【问题讨论】:

  • 您说的是手动内存管理。这种存储的目的是什么?拥有像链表(或直接可寻址的东西)这样存储可转换为不同数据类型的指针的动态数据结构不是更容易吗?请详细说明。
  • 在开始认真工作之前,您需要了解Data alignment。每个 16 位类型应该在一个 16 位边界,每个 32 位类型应该在一个 32 位边界……看看内存打包算法。
  • 据我所知,您需要一个结构或一个联合(或两者)。不要乱用字节和指针。
  • 收听@JefferyThomas 和@user3477950。您尝试做的事情比您出于各种与系统相关的原因尝试的幼稚方法要困难得多,而且编译器会为 免费 做一些事情。您的代码试图重新发明struct(或class),但从外观上看,您真正需要的似乎是union 提供的。阅读这些功能。
  • 有什么问题吗,辅导员?

标签: c++ c pointers


【解决方案1】:

从你描述问题的方式来看,你想要:

struct Foo
{
    int a, b;
    char c;
    float f;
};

但如果你真的需要动态地做(我不知道你为什么会这样做),你会写这样的:

struct Type
{
    size_t align;
    size_t size;
};

struct Field
{
    Type *type;
    size_t offset;
};

class ObjectType
{
private:
    std::vector<Field> fields;
public:
    void add_field(Type *t)
    {
        size_t off = fields.empty() ? 0 : fields.back().offset + fields.back.type->size;
        if (off % t->align)
            off += t->align - off % t->align;
        fields.push_back({t, off});
    }
};

...然后在 uint8_t 数组上使用 ObjectType

请注意,类型的大小和对齐之间没有一般关系,除了大小必须是对齐的倍数。例如,在某些系统上,long double 具有 align 4 和 size 12(但仅使用 10 个字节用于重要数据,2 个字节用于填充)。

也就是说,如果您希望它在平台之间兼容(例如,跨网络,但也适用于同一主机上的 32 位和 64 位代码),您需要做的远不止这些。

【讨论】:

  • "然后在 uint8_t 数组上使用 ObjectType" - 我希望您不是指基于指针的类型双关语,因为这是未定义的行为。
  • 在 unsigned、signed 和 plain char 以及仅包含它们的聚合上明确允许这样做
  • 是的,我知道这一点。然而,e。 G。 float 都不是(所以你必须按字节复制,你不能说*(float *)ptr = 3.14;
  • 您可以在 (char as described) 和任何其他类型之间键入双关语(前提是您遵守对齐方式,我这样做了。我想我应该提到 uint8_t 的初始数组必须对齐, 但它通常来自 malloc 无论如何都是对齐的)。
【解决方案2】:

像上面的答案一样,坚持使用结构:

typedef struct Foo{
    int a;
    int b;
    char c;
    float f;
}Foo;

Foo *bar = new(struct Foo);
bar->a = 1;
bar->b = 2;
bar->c = 'a';
bar->f = 11.4;
delete(bar);

【讨论】:

    猜你喜欢
    • 2013-12-31
    • 2014-05-13
    • 2019-04-13
    • 2022-08-17
    • 2010-11-01
    • 2023-04-06
    • 2021-03-14
    • 2022-01-24
    • 1970-01-01
    相关资源
    最近更新 更多