Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/131.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 关于联合和堆分配内存的问题_C++_Memory Management_Unions_Heap Memory - Fatal编程技术网

C++ 关于联合和堆分配内存的问题

C++ 关于联合和堆分配内存的问题,c++,memory-management,unions,heap-memory,C++,Memory Management,Unions,Heap Memory,我试图使用联合来更新一个线程中的字段,然后读取另一个线程中的所有字段。在实际的系统中,我有互斥锁来确保一切都是安全的。问题在于fieldB,在我不得不更改它之前,fieldB被声明为类似于字段A和C。但是,由于第三方驱动程序,fieldB必须与页面边界对齐。当我将字段B更改为分配valloc时,我遇到了问题 问题: 1) 是否有一种方法可以静态声明在页面边界上对齐的fieldB。基本上做和valloc相同的事情,但是在堆栈上 2) 当在堆上分配字段B或任何字段时,是否可以进行联合?。不知道这是否

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

问题: 1) 是否有一种方法可以静态声明在页面边界上对齐的fieldB。基本上做和valloc相同的事情,但是在堆栈上

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

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

#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;
}
#包括
#包括
#包括
#包括
课堂测试
{
公众:
测试(无效)
{
//字段B必须与页面边界对齐
//有没有办法在堆栈上执行此操作???
this->field.fieldB=(无符号字符*)valloc(10);
};
//我知道这很糟糕,这个班被当作
//一个全局结构。它包含在另一个类中。
无符号字符*pointerToFeelda(void)
{
return&this->field.fieldA[0];
}
无符号字符*PointerToFieldB(无效)
{
返回此->field.fieldB;
}
无符号字符*PointerToFieldC(void)
{
return&this->field.fieldC[0];
}
无符号字符*PointerToAllFields(void)
{
返回此->所有字段[0];
}
私人:
//在B字段为的情况下,该并集是否可能
//在堆上分配?
联盟
{
结构
{
无符号字符字段A[10];
//此字段必须与页面边界对齐
//是否有方法在堆栈上声明
无符号字符*字段B;
无符号字符字段C[10];
}场;
无符号字符所有字段[30];
};
};
int main()
{
试验;
strncpy((char*)test.PointerToFieldA(),“0123456789”,10);
strncpy((char*)test.PointerToFieldB(),“1234567890”,10);
strncpy((char*)test.PointerToFieldC(),“2345678901”,10);
伪字符[11];
伪[10]='\0';
strncpy(dummy,(char*)test.PointerToFieldA(),10);
printf(“%s\n”,虚拟);
strncpy(dummy,(char*)test.PointerToFieldB(),10);
printf(“%s\n”,虚拟);
strncpy(dummy,(char*)test.PointerToFieldC(),10);
printf(“%s\n”,虚拟);
char-allFields[31];
所有字段[30]='\0';
strncpy(allFields,(char*)test.PointerToAllFields(),30);
printf(“%s\n”,所有字段);
返回0;
}

我不这么认为-在堆栈上对齐有点复杂,因为您需要知道当前位置,分配足够的字节来消耗“当前”内存页,然后分配数据。在堆栈上,这不是通常的操作(即不对齐堆栈上的任何内容)

但是,某些编译器具有将对齐结构的杂注,MSVC具有可指定数据成员对齐方式的“”并且编译器将插入适当数量的字节

可以在堆上分配1个成员的情况下进行联合-联合将像往常一样包含所有字段,但堆分配的字段将只是一个指针


最后,valloc已经过时-您应该使用memalign或posix_memalign来代替。

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

我有点好奇,是否有可能为类重载新操作符,以强制特定成员位于页面边界上。我很快就拼凑了一些重载操作符来实现这一点。它会导致每次分配一整张额外的页面。它找到该字段所在位置的偏移量,然后按该量调整地址。由于额外的内存已分配(假设我计算正确),因此它是安全的。但是很难看

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

#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;
}

根据您对valloc的调用,您的意思是
fieldB
中包含的值需要与页面对齐。是这样吗?无论如何,我能想到的任何解决方案都会浪费多达PAGE_SIZE-1字节的空间,这是一个非常浪费的堆栈。为什么要在堆栈上分配它?您是对的,fieldB需要与页面对齐。我想没有必要在堆栈上分配。我只是好奇这是否可能?当所有东西都分配到堆栈上时,它似乎可以工作。当我使用valloc时,会发生可怕的碰撞。如果你有一个解决方案,其中所有的东西都在堆上,我打开了它。在上面的示例代码中,allFields并没有打印出所有的a-C字段,所以它不能像我预期的那样工作。我希望所有字段打印出字段A-C。它只打印字段A,然后再获取垃圾数据。所以它似乎对我不起作用。感谢关于使用memalign和posix_memalign的建议。到现在为止,还不需要页对齐内存。
new 00353FA0
allocation offset 86
address of fieldB 00355000
delete 00353FA0