Search code examples
c++arrays64-bitunions32-bit

C++ Union Array differs in 32/64 bits


My code:

union FIELD {
    int n;
    char c;
    const char *s;
    FIELD(){}
    FIELD(int v){ n = v; }
    FIELD(char v){ c = v; }
    FIELD(const char* v){ s = v; }
};

struct SF {
    const char* s0;
    char s1;
    int s2;
    const char* s3;
};

int main() {
    printf("sizeof(long) = %ld\n", sizeof(long));
    printf("now is %d bit\n", sizeof(long) == 8?64:32);

    FIELD arrField[] = {
        FIELD("any 8 words 0 mixed"), FIELD('d'), FIELD(251356), FIELD("edcba")
    };
    SF* sf0 = (SF*)&arrField;

    printf("sf0->s0 = %s, ", sf0->s0);
    printf("sf0->s1 = %c, ", sf0->s1);
    printf("sf0->s2 = %d, ", sf0->s2);
    printf("sf0->s3 = %s\n", sf0->s3);
}

When I use the default 64-bit execution output:

image

I add the compilation parameters in CMakeLists.txt:

set_target_properties(untitled PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")

It will compile the 32-bit program, then run and output:

image


My question is, how can I make a 64-bit program have the same output behavior as a 32-bit program?


Solution

  • Apply alignas(FIELD) to every single member variable of SF.

    Additionally you cannot rely on the size of long to tell 64 bit and 32 bit systems appart. Check the size of a pointer to do this. On some 64 bit systems long is 32 bit. This is the case for my system for example.

    Furthermore %ld requires a long parameter, but the sizeof operator yields size_t which is unsigned in addition to not necesarily matching long in size. You need to add a cast there to be safe (or just go with std::cout which automatically chooses the correct conversion based on the second operand of the << operator).

    union FIELD {
        int n;
        char c;
        const char* s;
        FIELD() {}
        FIELD(int v) { n = v; }
        FIELD(char v) { c = v; }
        FIELD(const char* v) { s = v; }
    };
    
    struct SF {
        alignas(FIELD) const char* s0;
        alignas(FIELD) char s1;
        alignas(FIELD) int s2;
        alignas(FIELD) const char* s3;
    };
    
    int main() {
        printf("sizeof(long) = %ld\n", static_cast<long>(sizeof(long)));
        printf("now is %d bit\n", static_cast<int>(sizeof(void*)) * 8);
    
        FIELD arrField[] = {
            FIELD("any 8 words 0 mixed"), FIELD('d'), FIELD(251356), FIELD("edcba")
        };
        SF* sf0 = (SF*)&arrField;
    
        printf("sf0->s0 = %s, ", sf0->s0);
        printf("sf0->s1 = %c, ", sf0->s1);
        printf("sf0->s2 = %d, ", sf0->s2);
        printf("sf0->s3 = %s\n", sf0->s3);
    }