(First of all, my OP had an error. Where it says "#ifndef DEFINE_ME" it should say "#ifdef DEFINE_ME".)
Okay, so this is super weird.
I've managed to get a minimal snippet that reproduces the issue:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
#include <fstream>
#include <cstdint>
#include <memory>
typedef std::uint8_t byte_t;
struct RGB{
byte_t r, g, b, a;
};
#define DEFINE_ME
int main(){
const int w = 20 * 8 * 4;
const int h = 18 * 8 * 4;
const size_t size = w * h * sizeof(RGB);
std::unique_ptr</*RGB*/RGB[]> pixels(new RGB[w * h]);
for (int y = 0; y < h; y++){
auto row = pixels.get() + y * w;
RGB px;
px.r = px.g = px.b = 0x55 + 0x55 * y / (h - 1);
px.a = 0x80;
for (int x = 0; x < w; x++){
#ifdef DEFINE_ME
row[x] = px;
#else
row[x].r = px.r;
row[x].g = px.g;
row[x].b = px.b;
row[x].a = px.a;
#endif
}
}
std::ofstream file("output.bin", std::ios::binary);
file.write((const char *)pixels.get(), size);
return 0;
}
|
Like I said, DEFINE_ME causes garbage to be written to the file.
However, every fourth byte in the file (file_position % 4 == 3) is set to 0x80!
Some other things I've tried:
* The issue goes away completely if all members of px are initialized to constant values.
* Adding a constructor to RGB doesn't make a difference, neither does initializing its members in the loop to constant values before setting them to variable values. This would be expected.
Looking at the disassembly, it seems all the compiler has generated for the entire nested loop was the RGB::a assignment to 0x80 and a rep stos of size / 4 DWORDs. So it seems to believe for some reason that the assignments from variable values should have no effect on the output.
As far as I can tell, this has to be a compiler bug.