标准库和本地的包含顺序 headers

Order of includes with standard libraries and local headers

我正在生成位图文件。该程序每次都会编译,但在某些时候根据 #include 的顺序,它会给出好的或损坏的 .bmp 文件。
它来自一个教程,所有文件都是 here.

我的结构如下:

main.cpp

#include <iostream>
#include "Bitmap.h"
using namespace std;
int main() {
    Bitmap bitmap(800, 600);
    bitmap.write("test.bmp");
}

Bitmap.h

#include <string>
#include <cstdint>
#include <memory>
using namespace std;
class Bitmap {
private:
    int m_width{0};
    int m_height{0};
    unique_ptr<uint8_t[]> m_pPixels{nullptr};
public:
    Bitmap(int width, int height);
    bool write(string filename);
};

BitmapFileHeader.h

#include <cstdint>
using namespace std;
#pragma pack(2)
struct BitmapFileHeader {
    char header[2] { 'B', 'M' };
    int32_t fileSize;
    int32_t reserved { 0 };
    int32_t dataOffset;
};

BitmapInfoHeader.h

#include <cstdint>
using namespace std;
#pragma pack(2)
struct BitmapInfoHeader {
    int32_t headerSize{40};
    int32_t width;
    int32_t height;
    int16_t planes{1};
    int16_t bitsPerPixel{24};
    int32_t compression{0};
    int32_t dataSize{0};
    int32_t horizontalResolution{2400};
    int32_t verticalResolution{2400};
    int32_t colors{0};
    int32_t importantColors{0};
};

Bitmap.cpp

#include <fstream>
#include "Bitmap.h"
#include "BitmapInfoHeader.h"
#include "BitmapFileHeader.h"

using namespace std;

Bitmap::Bitmap(int width, int height): m_width(width), m_height(height), m_pPixels(new uint8_t[width * height * 3]{ }) {}

bool Bitmap::write(string filename) {
    BitmapFileHeader fileHeader;
    BitmapInfoHeader infoHeader;

    fileHeader.fileSize = sizeof(BitmapFileHeader) + sizeof(BitmapInfoHeader) + m_width * m_height * 3;
    fileHeader.dataOffset = sizeof(BitmapFileHeader) + sizeof(BitmapInfoHeader);

    infoHeader.width = m_width;
    infoHeader.height = m_height;

    ofstream file;
    file.open(filename, ios::out | ios::binary);
    file.write((char *)&fileHeader, sizeof(fileHeader));
    file.write((char *)&infoHeader, sizeof(infoHeader));
    file.write((char *)m_pPixels.get(), m_width*m_height*3);
    file.close();
    return true;
}

现在在 Bitmap.cpp 中按此顺序一切正常。当我更改顺序以便 #include <fstream> 排在最后时,它仍然编译没有错误但生成损坏的文件。
BitmapInfoHeader.hBitmapInfoHeader.h 只是持有一个结构,每个结构中都有一些 int32_t 变量,根本不使用 fstream
为什么会这样?

没有 mcve 就无法确定。但是很多时候,当包含顺序中断编译时,它是由至少一个 header 未能包含其所有依赖项引起的。在这种情况下,如果包含缺失依赖项的另一个 header 恰好包含在损坏的 header 之前,则会导致错误被隐藏。

编辑添加的代码:

如果将标准 header 移动到 #pragma pack(2) 下面,就会破坏标准 class 的定义。您应该始终在 header 秒内推送和弹出打包编译指示。

错误在BitmapInfoHeader.h

// issue #1:  There is no guard to prevent re-entry into you header.

#pragma once   // this should fix that, you can also place a classic 
               // #ifndef / #define / #endif guard, as advised by the 
               // C++ Core Guidelines  
               // https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines 

#include <cstdint>
using namespace std; // Issue #2: 
                     // NEVER place a "using namespace std;" in a header 
                      // file.  BTW, it is not even needed for this
                      // file to compile.
                      // And NEVER place a "using namespace ...;"
                      // in the global namespace in a header file. 

// issue # 3.  Any pack pragma MUST be preceded by a push, like this:

#pragma pack(2)                // <-- This pack pragma breaks all include
                               // files that will follow this one.

#pragma pack(push)
#pragma pack(1)                // use pack(1) to signify full packing,
                               // so when someone else reads your code, 
                               // they won't need to read the whole 
                               // struct definition, to figure out 
                               // what it is you are trying to
                               // accomplish. 

struct BitmapInfoHeader {
    int32_t headerSize{40};
    int32_t width;
    int32_t height;
    int16_t planes{1};
    int16_t bitsPerPixel{24};
    int32_t compression{0};
    int32_t dataSize{0};
    int32_t horizontalResolution{2400};
    int32_t verticalResolution{2400};
    int32_t colors{0};
    int32_t importantColors{0};
};

//  After a #pragma(push), don't forget to restore the original 
//  packing, otherwise, you are violating the One Definition Rule.
//  If you do not restore, everything after including this file
//  will exhibit undefined behavior.  

#pragma pack(pop)

文件Bitmap.h也有一些相同的问题。