user153498
user153498

Reputation:

Initialize a struct inside a union (C++)

I'm creating a very limited, domain-specific x86 assembler in C++ (Visual Studio 2010) that dynamically generates instructions, writes it to memory, and executes it, all at runtime. First I write them to a temporary byte stream, and then write the entire stream to executable memory in one memcpy.

I use the following code for constructing a movsd [imm32], xmm1 instruction:

typedef unsigned char byte;
enum SSE2Register;

void WriteValueToMemory(double* dest, SSE2Register source)
{
    union
    {
        struct
        {
            byte insts[4];
            double* dest;
        };

        byte bytes[8];
    } movsd = 
    {
        // movsd [imm32], xmm1
        0xF2, 0x0F, 0x11, // Opcode
        0x05 + (8 * source), // ModR/M 
        dest // imm32
    };

    _stream.Write(movsd.bytes, sizeof(movsd.bytes));
}

This code works: the three opcode bytes and the ModR/M byte are written to insts, the destination (imm32) is written to dest, and bytes contains the entire instruction in raw bytes, ready to be written to the instruction stream.

However, I am curious as to whether this method of initializing the union is safe/portable. Is it OK to initialize the four values of insts and the value of dest within a single set of braces?

In other words, is this the correct, portable way of doing this, or should I do it a different way?

Thanks!

Upvotes: 1

Views: 713

Answers (1)

Mooing Duck
Mooing Duck

Reputation: 66981

http://msdn.microsoft.com/en-us/library/z2cx9y4f.aspx

Anonymous Structures

A Microsoft C extension allows you to declare a structure variable within another structure without giving it a name. These nested structures are called anonymous structures. C++ does not allow anonymous structures.

You can access the members of an anonymous structure as if they were members in the containing structure.

However, you don't need a union for what you're doing.

void WriteValueToMemory(double* dest, SSE2Register source)
{
    struct
    {
        byte insts[4];
        double* dest;
    } movsd = 
    {  // movsd [imm32], xmm1
        0xF2, 0x0F, 0x11, // Opcode
        0x05 + (8 * source), // ModR/M 
        dest // imm32
    };

    _stream.Write(&movsd, sizeof(movsd));
}

Upvotes: 2

Related Questions