C++ 静态数组缓冲区分配

C++ 静态数组缓冲区分配,c++,arrays,buffer,C++,Arrays,Buffer,假设我定义了一个数组float floatBuffer[4],我有一个结构:struct vec3{float x,y,z;}myVec 在vec3赋值之前,我赋值:floatBuffer[3]=0.0f (如果可能的话,)我可以通过什么方式将myVec分配给floatBuffer[0](二进制副本),以便 floatBuffer[0]==myVec.x floatBuffer[1]==myVec.y floatBuffer[2]==myVec.z 浮动缓冲区[3]==0.0f ? 显

假设我定义了一个数组
float floatBuffer[4]
,我有一个结构:
struct vec3{float x,y,z;}myVec

在vec3赋值之前,我赋值:
floatBuffer[3]=0.0f

(如果可能的话,)我可以通过什么方式将
myVec
分配给
floatBuffer[0]
(二进制副本),以便

  • floatBuffer[0]==myVec.x

  • floatBuffer[1]==myVec.y

  • floatBuffer[2]==myVec.z

  • 浮动缓冲区[3]==0.0f

    ?

    • 显而易见的答案是:

      floatBuffer[0] = myVec.x;
      floatBuffer[1] = myVec.y;
      floatBuffer[2] = myVec.z;
      
      如果您愿意对结构布局进行假设,并且编译器为直接赋值生成了蹩脚的代码,请记录您的假设并执行
      memcpy

      static_assert(sizeof(myVec) == sizeof(float[3]), "myVec should not have padding");
      
      memcpy(&floatBuffer[0], &myVec, sizeof(myVec));
      

      该标准确实指出,即使在标准布局结构中(但不是在开头),也可能存在填充,因此二进制副本可能不可移植。但是,给定特定的系统和包装说明(查找
      #pragma pack
      ),您可能只能使用
      memcpy

      您可以尝试以下操作:

      #include <cstring>
      #include <algorithm>
      #include <iterator>
      #include <iostream>
      
      // look up your compiler's documentation
      //#pragma pack(4) 
      
      struct fs {
       float x, y, z;
      };
      
      int main() {
       fs b = {1.0, 2.0, 3.0};
       float p[ 4 ] = {0};
       static_assert( sizeof b == sizeof p - 1, "warning: padding detected!" );
       std::memcpy(&p[ 0 ], &b, sizeof p - 1);
       std::copy(&p[ 0 ], &p[ 0 ] + 3, std::ostream_iterator<float>(std::cout, "\n"));
      }
      
      #包括
      #包括
      #包括
      #包括
      //查找编译器的文档
      //#布拉格语包(4)
      结构fs{
      浮动x,y,z;
      };
      int main(){
      fs b={1.0,2.0,3.0};
      浮点p[4]={0};
      静态_断言(sizeof b==sizeof p-1,“警告:检测到填充!”);
      标准::memcpy(&p[0],&b,p-1的大小);
      std::copy(&p[0],&p[0]+3,std::ostream_迭代器(std::cout,“\n”);
      }
      
      可以使用memcpy,但是如上所述,memcpy可能会因包装不同而易碎

      我认为这里最好的解决方案是使用多个语句,而不是过于复杂

      floatBuffer[0] = myVec.x; 
      floatBuffer[1] = myVec.y; 
      floatBuffer[2] = myVec.z; 
      
      用显而易见的方式来做。。。 代码很清楚正在发生什么,您可以让编译器为您优化代码

      我确实想到了一个问题,
      这就是为什么要使用浮点数组而不是vec3或vec3数组(这将允许一次赋值)

      您可以为此编写一个函数

      struct vec3{float x,y,z;} myVec;
      
      float* operator<< (float t[4], vec3 v) {
        t[0] = v.x; t[1] = v.y; t[2] = v.z; t[3] = 0;
        return t;
      }
      
      int main() {
        float test[4];
        test << myVec; // now do the assignment 'in one go'
        return 0;
      }
      
      structvec3{float x,y,z;}myVec;
      
      float*操作符,如果他控制了声明,他可以执行
      float floatBuffer[4]={myVec.x,myVec.y,myVec.z}
      @xcrypt如果你把它放在一个函数中,然后调用那个函数,它算“一次性”吗?(对我来说)这只是字面上的复制数据。这两者之间没有区别,只是使用您建议的指针需要编译器以某种方式布置结构。@xcrypt哦,对了,我忘了。它不能“仅仅选取所有字节并复制它们”,因为计算机并不神奇。也就是说,这并不意味着生成的程序集将有一个循环。我怀疑赋值和memcpy会产生非常相似的生成代码。@xcrypt哦,它们可以一次复制“多个字节”,但数量有限。因为最终,下面的硬件对一次可以传输的字节数有限制。总线没有无限的带宽。由于
      floatbuffer
      是静态的(我从标题中假设这一点),所有数组元素都将初始化为零,除非您为它们提供其他非零编译时常量。当然,您以后可以修改它们。指定初始值有问题吗?因为我希望floatbuffer能够表示任何内容。例如,在DirectX顶点缓冲区中表示顶点,您可能会考虑要使用的类型的联合。