Home > OS >  Is my compiler turning my enum into bitfields? [duplicate]
Is my compiler turning my enum into bitfields? [duplicate]

Time:09-21

I have a structure that looks like this:

struct UploadConfig {
private:
    const void *                m_data;                  //  4 bytes (32bit)
    glm::u16vec4                m_size;                  // 12 bytes (uint16 * 4 =  8)
    uint8                       m_mipmapsCount;
    TextureDim::Type            m_depthType;
    TextureInternalFormat::Type m_internalFormat;   
    TextureUploadFormat::Type   m_uploadFormat;          // 16 bytes
    TextureUploadComp::Type     m_uploadCompType;
    uint8                       m_swizzleR          :3;     
    uint8                       m_swizzleG          :3;
    uint8                       m_swizzleB          :3;
    uint8                       m_swizzleA          :3;
    bool                        m_minFilter         :1;
    bool                        m_minmipFilterUsed  :1;
    bool                        m_minmipFilter      :1;
    bool                        m_maxFilter         :1;
    bool                        m_edgeClampX        :1;
    bool                        m_edgeMirrorX       :1;
    bool                        m_edgeClampY        :1;
    bool                        m_edgeMirrorY       :1;
    bool                        m_edgeClampZ        :1;
    bool                        m_edgeMirrorZ       :1; // 20 bytes probably
};

const int iogwhgakfj = sizeof UploadConfig;  // this is reported as 16 (???)

Where the enums are defined as uint8 like this:

struct TextureDim {
    enum Type : uint8 {
        dim2D,
        dim3D,
        dimCubic
    };
};

But the size of this structure is really odd to me at 16 bytes, I expected it to be larger at 20 or even 24. Is the compiler turning my enums into bitfields behind my back? I mean... nice, but also seems weird it would do that with an enum type, and not a series of boolean. (Without the bitfields specified, this structure's size is 28)

edit

I tried adding some curveballs to confuse the compiler, but it still reports a size of 16 in the IDE (hovering over the value iogwhgakfj)

My pitches were:

void UploadConfig::setMinFilter() {
    // there's no way the compiler can predict this
    m_minFilter = (uintptr(&m_internalFormat) & 7) == (uintptr(&m_uploadCompType) & 7);
}

Curiously too, it refuses to compute offsetof(TextureUploadConfig, m_uploadCompType); in the IDE, but will do this for the values of m_mipmapsCount and the members that appear prior to it.

Conclusion

It was because the enum wasn't defined yet. Define your enum types before you use them, because Visual Studio will very nicely highlight the syntax as if it were. Also maybe don't mess your code up so bad that you can't compile for a week straight.

CodePudding user response:

This is not a proper answer. Rather an extended comment with formatting.

On my machine (which has 8-byte pointers), I'm seeing this:

              m_data 0
              m_size 8
      m_mipmapsCount 16
         m_depthType 17
    m_internalFormat 18
      m_uploadFormat 19
    m_uploadCompType 20
          m_swizzleR 21[.....210]
          m_swizzleG 21[..543...]
          m_swizzleB 22[.....210]
          m_swizzleA 22[..543...]
         m_minFilter 22[.6......]
  m_minmipFilterUsed 22[7.......]
      m_minmipFilter 23[.......0]
         m_maxFilter 23[......1.]
        m_edgeClampX 23[.....2..]
       m_edgeMirrorX 23[....3...]
        m_edgeClampY 23[...4....]
       m_edgeMirrorY 23[..5.....]
        m_edgeClampZ 23[.6......]
       m_edgeMirrorZ 23[7.......]

The quick-and-dirty code for that output is:

#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <cstring>

using std::cout;
using std::memset;
using std::ostringstream;
using std::setw;
using std::string;

using uint8 = unsigned char;
using uint16 = unsigned short;

namespace glm {
struct u16vec4 { uint16 data[4]; };
}

struct TextureDim { enum Type : uint8 { }; };
struct TextureInternalFormat { enum Type : uint8 { }; };
struct TextureUploadFormat { enum Type : uint8 { }; };
struct TextureUploadComp { enum Type : uint8 { }; };

struct UploadConfig {
    const void *                m_data;                  //  4 bytes (32bit)
    glm::u16vec4                m_size;                  // 12 bytes (uint16 * 4 =  8)
    uint8                       m_mipmapsCount;
    TextureDim::Type            m_depthType;
    TextureInternalFormat::Type m_internalFormat;
    TextureUploadFormat::Type   m_uploadFormat;          // 16 bytes
    TextureUploadComp::Type     m_uploadCompType;
    uint8                       m_swizzleR          :3;
    uint8                       m_swizzleG          :3;
    uint8                       m_swizzleB          :3;
    uint8                       m_swizzleA          :3;
    bool                        m_minFilter         :1;
    bool                        m_minmipFilterUsed  :1;
    bool                        m_minmipFilter      :1;
    bool                        m_maxFilter         :1;
    bool                        m_edgeClampX        :1;
    bool                        m_edgeMirrorX       :1;
    bool                        m_edgeClampY        :1;
    bool                        m_edgeMirrorY       :1;
    bool                        m_edgeClampZ        :1;
    bool                        m_edgeMirrorZ       :1;
};

const int iogwhgakfj = sizeof(UploadConfig);

static int diff(void* b, void* m) {
    auto bb = static_cast<char*>(b);
    auto mm = static_cast<char*>(m);
    return static_cast<int>(mm - bb);
}

static string zrange(void* b, size_t len) {
    auto bb = static_cast<unsigned char*>(b);
    ostringstream ss;
    auto sep = "";
    for (size_t pos = 0; pos < len;   pos) {
        if (bb[pos] == 0xFF) continue;
        ss << sep << pos << "[";

        auto u = bb[pos];
        if ((u & 0b1000'0000) == 0) ss << "7"; else ss << ".";
        if ((u & 0b0100'0000) == 0) ss << "6"; else ss << ".";
        if ((u & 0b0010'0000) == 0) ss << "5"; else ss << ".";
        if ((u & 0b0001'0000) == 0) ss << "4"; else ss << ".";
        if ((u & 0b0000'1000) == 0) ss << "3"; else ss << ".";
        if ((u & 0b0000'0100) == 0) ss << "2"; else ss << ".";
        if ((u & 0b0000'0010) == 0) ss << "1"; else ss << ".";
        if ((u & 0b0000'0001) == 0) ss << "0"; else ss << ".";

        ss << "]";
        sep = " ";
    }

    return ss.str();
}

int main() {
    cout << "Size of UploadConfig: " << iogwhgakfj << "\n";
    UploadConfig u;
#define DIFF(member) cout << setw(20) << #member << " " << diff(&u, &u.member) << "\n"
#define DIFFX(bitmember) memset(&u, 0xFF, sizeof u); u.bitmember = 0; cout << setw(20) << #bitmember << " " << zrange(&u, sizeof u) << "\n"
    DIFF(m_data);
    DIFF(m_size);
    DIFF(m_mipmapsCount);
    DIFF(m_depthType);
    DIFF(m_internalFormat);
    DIFF(m_uploadFormat);
    DIFF(m_uploadCompType);
    DIFFX(m_swizzleR);
    DIFFX(m_swizzleG);
    DIFFX(m_swizzleB);
    DIFFX(m_swizzleA);
    DIFFX(m_minFilter);
    DIFFX(m_minmipFilterUsed);
    DIFFX(m_minmipFilter);
    DIFFX(m_maxFilter);
    DIFFX(m_edgeClampX);
    DIFFX(m_edgeMirrorX);
    DIFFX(m_edgeClampY);
    DIFFX(m_edgeMirrorY);
    DIFFX(m_edgeClampZ);
    DIFFX(m_edgeMirrorZ);
#undef DIFF
#undef DIFFX
}
  • Related