gpt4 book ai didi

c++ - 关于 union 和堆分配内存的问题

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:05:57 25 4
gpt4 key购买 nike

我试图使用 union 来更新一个线程中的字段,然后在另一个线程中读取所有字段。在实际系统中,我有互斥锁来确保一切都是安全的。问题出在 fieldB 上,在我不得不更改它之前,fieldB 被声明为类似于字段 A 和 C。但是,由于第三方驱动程序,fieldB 必须与页面边界对齐。当我将字段 B 更改为使用 valloc 分配时,我遇到了问题。

问题:1) 有没有办法在页面边界上静态声明 fieldB 对齐。基本上做与 valloc 相同的事情,但在堆栈上?

2) 当字段 B 或任何字段正在堆上分配时,是否可以进行 union ?不确定这是否合法。

这是我正在试验的一个简单的测试程序。这不起作用,除非您像字段 A 和 C 一样声明字段 B,并在公共(public)方法中进行明显的更改。

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

class Test
{
public:
Test(void)
{
// field B must be alligned to page boundary
// Is there a way to do this on the stack???
this->field.fieldB = (unsigned char*) valloc(10);
};

//I know this is bad, this class is being treated like
//a global structure. Its self contained in another class.
unsigned char* PointerToFieldA(void)
{
return &this->field.fieldA[0];
}

unsigned char* PointerToFieldB(void)
{
return this->field.fieldB;
}

unsigned char* PointerToFieldC(void)
{
return &this->field.fieldC[0];
}

unsigned char* PointerToAllFields(void)
{
return &this->allFields[0];
}

private:
// Is this union possible with field B being
// allocated on the heap?
union
{
struct
{
unsigned char fieldA[10];

//This field has to be alligned to page boundary
//Is there way to be declared on the stack
unsigned char* fieldB;
unsigned char fieldC[10];
} field;

unsigned char allFields[30];
};
};


int main()
{
Test test;

strncpy((char*) test.PointerToFieldA(), "0123456789", 10);
strncpy((char*) test.PointerToFieldB(), "1234567890", 10);
strncpy((char*) test.PointerToFieldC(), "2345678901", 10);

char dummy[11];
dummy[10] = '\0';

strncpy(dummy, (char*) test.PointerToFieldA(), 10);
printf("%s\n", dummy);

strncpy(dummy, (char*) test.PointerToFieldB(), 10);
printf("%s\n", dummy);

strncpy(dummy, (char*) test.PointerToFieldC(), 10);
printf("%s\n", dummy);

char allFields[31];
allFields[30] = '\0';
strncpy(allFields, (char*) test.PointerToAllFields(), 30);
printf("%s\n", allFields);

return 0;
}

最佳答案

我不认为您可以将 fieldB 声明为指针并获得所需的行为(假设我正确理解了问题)。为了使 union 在您使用时有意义,您需要在 union 中将其声明为数组。

我很好奇是否可以重载类的 new 运算符以强制特定成员位于页面边界上。我很快就拼凑了重载的运算符来做到这一点。它会导致每次分配一个完整的额外页面。它找到该字段所在位置的偏移量,然后按该量调整地址。由于分配了额外的内存(假设我计算正确),这将是安全的。不过很丑。

它将分配偏移量填充到类中的一个成员中,以便它知道要“取消偏移”指针以释放它的量。这真是可怕的代码。作为实验似乎还可以,但在生产代码中就不太好了。

#define PAGE_SIZE 0x1000

class test
{
public:
int allocoffset;
void* operator new( size_t );
void operator delete( void* );
union
{
__declspec( align(4096)) struct
{
unsigned char fieldA[10];

//This field has to be alligned to page boundary
//Is there way to be declared on the stack
unsigned char fieldB[10];
unsigned char fieldC[10];
} field;

unsigned char allFields[30];
};
};

void* test::operator new(size_t size)
{
// Allocate an entire extra page so we can offset it by any amount
// less than the page size to ensure alignment of fieldB
unsigned char *p = (unsigned char*)malloc( sizeof( test ) + PAGE_SIZE );
uintptr_t addr;
uintptr_t diff;

std::cout << "new " << (void*)p << std::endl;

// now offset the returned memory by the amount needed to align
// fieldB on a page boundary.
addr = (uintptr_t)p + (uintptr_t)( offsetof( test, field.fieldB ));

diff = PAGE_SIZE - ( addr & (PAGE_SIZE - 1 ));

p += diff;

((test*)p)->allocoffset = diff;

return p;
}

void test::operator delete( void *p )
{
// offset by appropriate amount that we allocated it by
p = (void*)( (unsigned char*)p - ((test*)p)->allocoffset );
std::cout << "delete " << p << std::endl;
free(p);
}

int main()
{
test *t;

t = new test;

std::cout << "allocation offset " << t->allocoffset << std::endl;
std::cout << "address of fieldB " << (void*)&t->field.fieldB << std::endl;

delete t;
}

这是示例输出:

new 00353FA0
allocation offset 86
address of fieldB 00355000
delete 00353FA0

关于c++ - 关于 union 和堆分配内存的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3579656/

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