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
}