【问题标题】:warning C4316: object allocated on the heap may not be aligned 16警告 C4316:在堆上分配的对象可能未对齐 16
【发布时间】:2013-11-20 19:11:23
【问题描述】:

重要信息:

  • 开发操作系统:Windows 8.1 64 位
  • 目标操作系统:Windows 8.1 64 位
  • IDE:Visual Studio 2013 专业版
  • 语言:C++

问题:

通过 IDE 编译我的静态库项目时收到以下警告:

warning C4316: ... : object allocated on the heap may not be aligned 16

我可以简单地忽略此警告...但我假设它的存在是有原因的,并且希望至少了解它的含义以及它对未来可能产生的影响。

我认为这行代码与问题有关,在我的 Win32 窗口包装类中调用:

m_direct3D = new Direct3D(this);

m_direct3D 是一个指向我的 Direct3D 包装类的指针。

这是包装器的头文件(我承认它需要修剪):

#pragma once

// Windows
#include <d3d11.h>
#include <DirectXMath.h>

// Standard
#include <stdint.h>
#include <vector>

// JGlib
#include "Window.h"

namespace JGlib
{
    namespace Graphics
    {
        class Direct3D
        {
        public:
            // Construtor and destructor
            Direct3D(const JGlib::Graphics::Window* window);
            ~Direct3D();

            // Public methods
            void Initialise();
            void BeginDraw();
            void Draw();
            void EndDraw();

        private:
            // Private methods

            // Private member variables
            const Window*               m_window;
            ID3D11Device*               m_device;
            IDXGIAdapter*               m_adapter;
            DXGI_ADAPTER_DESC           m_adapterDescription;
            uint32_t                    m_videoCardMemory;
            IDXGIFactory*               m_factory;
            IDXGIOutput*                m_monitor;
            DXGI_MODE_DESC*             m_displayModes;
            uint32_t                    m_numberOfModes;    
            DXGI_RATIONAL               m_refreshRate;
            DXGI_SWAP_CHAIN_DESC        m_swapChainDescription;
            D3D_FEATURE_LEVEL           m_featureLevel;
            ID3D11DeviceContext*        m_deviceContext;
            IDXGISwapChain*             m_swapChain;
            ID3D11Texture2D*            m_backBuffer;
            ID3D11RenderTargetView*     m_renderTargetView;
            ID3D11Texture2D*            m_depthStencilBuffer;
            D3D11_TEXTURE2D_DESC        m_depthBufferDescription;
            D3D11_DEPTH_STENCIL_DESC    m_depthStencilDescription;
            ID3D11DepthStencilState*    m_depthStencilState;
            ID3D11DepthStencilView*     m_depthStencilView;
            D3D11_RASTERIZER_DESC       m_rasterDescription;
            D3D11_VIEWPORT              m_viewport; 
            float                       m_fieldOfView;
            float                       m_screenAspectRatio;
            ID3D11RasterizerState*      m_rasterState;
            DirectX::XMMATRIX           m_projectionMatrix;
            DirectX::XMMATRIX           m_worldMatrix;
            DirectX::XMMATRIX           m_orthographicMatrix;
            float                       m_screenDepth;
            float                       m_screenNear;
        };
    }
}

我尝试用谷歌搜索该问题,但发现的信息很少。我发现的信息我不明白。

最后,我要问的是:

  1. C4316 是什么意思?
  2. 是什么导致我的代码出现这种情况?
  3. 如果我忽略它,这会对未来产生什么影响?
  4. 如何“修复”导致出现此警告的问题?

其他信息:

当我将 Visual Studio 的配置管理器更改为针对 x64 进行编译时,不会出现此问题。

【问题讨论】:

  • 这在 DirectXMath Programming Guide on MSDNType Usage Guidelines 中得到解决。简而言之,不要使用XMMATRIX,如果要移植到32位x86和ARM,请使用XMFLOAT4X4。如果您仅使用 x64,则堆分配默认为 16 字节对齐。

标签: c++ compiler-errors visual-studio-2013


【解决方案1】:

C4316 是什么意思?

C4316 是错误代码。这是一个唯一标识符,可以轻松找到the documentation

是什么导致了我的代码?

DirectX::XMMATRIX 类的用法。该类的实例必须在 16 字节边界上对齐。编译器确保每当您在堆栈或全局范围内创建JGLib::Graphics::Direct3D 实例时,它将正确对齐它,但如果您在堆上动态分配实例,编译器无法保证对象将对齐正确,因为malloc() 和朋友通常只保证 8 字节对齐。

如果我忽略它,这会对未来产生什么影响?

由于SSE 指令对未对齐的数据进行操作,您的代码在访问这些矩阵实例时可能会崩溃。

如何“修复”导致出现此警告的问题?

正如文档所建议的,您需要覆盖类的 operator newoperator delete 以保证 16 字节对齐。您可以使用_aligned_malloc()_aligned_free() 分配和释放在较大对齐上对齐的内存。

【讨论】:

  • 非常感谢您提供结构良好且清晰的答案。最后,我重新编写了我的代码,使它根本不在堆上分配,完全避免了这个问题。
【解决方案2】:

您需要覆盖 new 和 delete 运算符,如下所示:

__declspec(align(16)) class MyClass
{
    public:
    DirectX::XMMATRIX           m_projectionMatrix;

    virtual ~MyClass()
    {
    }

    void* operator new(size_t i)
    {
        return _mm_malloc(i,16);
    }

    void operator delete(void* p)
    {
        _mm_free(p);
    }
};

【讨论】:

  • 完全成功,这真的很烦人,非常感谢! :)
  • 在针对 XboxOne 的 vs2017 中,这是一个错误。虚幻引擎中重载了 new 和 delete 运算符。您知道如何修改新重载的签名以获取 align() 元数据吗?或者我应该只是抑制错误?对我来说似乎是一个真正无知的变化。微软的部分没有远见。我的班级没有任何东西需要 64 字节对齐。现在他们希望我为我创建的每一个类都重载新的。
【解决方案3】:

如果您查看预处理代码,您可能会在其中找到类似 __declspec(align(16)) 的内容,请求以 16 个字节对齐,而 new 可能不会在该约束下对齐。对应http://msdn.microsoft.com/en-us/library/vstudio/dn448573.aspx可以通过Override operator new and operator delete for over-aligned types so that they use the aligned allocation routines—for example, _aligned_malloc and _aligned_free.修复

【讨论】:

    【解决方案4】:

    DirectX::XMMATRIX 包含 SSE 数据(并因此标记为__declspec(align(16)),因此需要在 16B 边界上对齐,否则访问它的指令会导致访问冲突。

    警告告诉您,不能保证 operator new 返回的内存是 16B 对齐的。

    您可以将对象创建为全局变量或局部变量吗?这样编译器可以强制对齐。如果不能,您可以为使用_aligned_malloc_aligned_free 实现的Direct3D 类提供重载的newdelete

    【讨论】:

      猜你喜欢
      • 2014-03-20
      • 2010-12-10
      • 1970-01-01
      • 2013-08-10
      • 2023-03-16
      • 2013-01-25
      • 1970-01-01
      • 1970-01-01
      • 2018-04-03
      相关资源
      最近更新 更多