0

What is the C equivalent of this C# code?

[StructLayout(LayoutKind.Explicit)]
struct Test
{
    [FieldOffset(0)] int a;  // Integer at byte offset 0
    [FieldOffset(1)] int b;  // Integer at byte offset 1
    [FieldOffset(3)] int c;  // Integer at byte offset 3
};

(I don't care if it's non-portable, e.g. int is assumed to be 4 bytes, etc.)

user541686
  • 205,094
  • 128
  • 528
  • 886
  • I would have thought that even if they are overlapping fields, they should still be aligned properly. Is that actually valid on any platform? – Jeff Mercado Aug 25 '11 at 00:51
  • @Jeff: AFAIK x86 doesn't care. (http://stackoverflow.com/questions/548164/mis-aligned-pointers-on-x86/548411#548411) – user541686 Aug 25 '11 at 00:52
  • It's one thing for a pointer, but it's another for struct members AFAIK. – Jeff Mercado Aug 25 '11 at 00:53
  • @Jeff: It's completely fine, the compiler can do unaligned read magic if necessary. [Take a look at `bpb33` here](http://seas.ucla.edu/~mkampe/cs111.wq11/docs/freebsd/bpb_h.txt). – user541686 Aug 25 '11 at 00:58

6 Answers6

2

This seems to work fine under Visual Studio:

#pragma pack(push)

#pragma pack(1)
typedef union
{
    int a;
    struct
    {
        char unused0;
        int b;
    };
    struct
    {
        char unused1;
        char unused2;
        char unused3;
        int c;
    };
} Test;

#pragma pack(pop)
Jeff Mercado
  • 129,526
  • 32
  • 251
  • 272
  • But apparently you're not satisfied with either of those particular solutions. This on the other hand should meet your expectations right? Direct access to the `int` members aligned as specified. What else would you expect? – Jeff Mercado Aug 25 '11 at 01:22
  • Jeff, I think the question has not been posed precisely. You and I both assumed he was asking how to build a C data structure with explicit layout, and apparently that is not the case. – Cheeso Aug 25 '11 at 01:28
  • @Jeff: My apologies -- I didn't notice that your structs are anonymous, and that the fields are directly accessible. It's less than ideal but definitely a usable answer and different from the others, +1; thanks! – user541686 Aug 25 '11 at 01:39
1

Here is a macro that should work across clang, gcc and msvc (haven't tested the msvc version):

#define YDUMMY(suffix, size) char dummy##suffix[size]
#define XDUMMY(suffix, size) YDUMMY(suffix, size)
#define DUMMY(size) XDUMMY(__COUNTER__, size)
#ifdef __GNUC__
#define EXPLICIT_UNION_START(name) union Test {
#define EXPLICIT_UNION_END() };
#define EXPLICIT_OFFSET_FIELD(foff, ftype, fname) struct __attribute__((packed)) { DUMMY(foff); ftype fname; };
#elif defined(_MSC_VER)
#define EXPLICIT_UNION_START(name) #pragma pack(push, 1) \
union Test {
#define EXPLICIT_UNION_END() }; \
#pragma pack(pop)
#define EXPLICIT_OFFSET_FIELD(foff, ftype, fname) struct { DUMMY(foff); ftype fname; };
#else
#error "What compiler is this?"
#endif

EXPLICIT_UNION_START(Test)
    EXPLICIT_OFFSET_FIELD(0, int, a)
    EXPLICIT_OFFSET_FIELD(1, int, b)
    EXPLICIT_OFFSET_FIELD(3, int, c)
EXPLICIT_UNION_END()

Thanks to unnamed fields, the syntax to access your defined fields is not polluted by dummy names:

int main() {
    union Test t;
    t.b = 13;
    printf("offset a = %zx\n", offsetof(union Test, a));
    printf("offset b = %zx\n", offsetof(union Test, b));
    printf("offset c = %zx\n", offsetof(union Test, c));
    printf("t.b = %d\n", t.b);
    return 0;
}
Ace
  • 41
  • 1
  • 4
0

How about this.

union u_t {
    struct {
        int V;
    } a;
    struct {
        byte dummy;
        int V;
    } b;
    struct {
        byte dummy1;
        byte dummy2;
        byte dummy3;
        int V;
    } c;
};

The dummy fields are used to force offsets. I think some compilers can force field or struct alignment, so you need to insure when you compile, that option is off. See the pragma pack directive. The way to get to the a, b, c values is to reference the V field within each respective struct in the union. Eg if u is of type u_t, then

  u.c.V = 17;
Cheeso
  • 189,189
  • 101
  • 473
  • 713
  • That doesn't work because then I can't read/write `c` as though it were an integer. – user541686 Aug 25 '11 at 01:03
  • Well then change the names to struct1 struct2 struct3. As I said in my answer originally, you reference the `c` value with `u.c.V`. V is an integer. If you are concerned about the symbol names, change them. – Cheeso Aug 25 '11 at 01:09
  • So what I'm understanding is "there's no direct translation for this in Visual C++" -- is that correct? – user541686 Aug 25 '11 at 01:12
  • 2
    Well I don't understand the question. When I read "what's the equivalent", I thought you were looking for a data structure that had similar layout, which would allow you to reference different 4-byte int values pointing into the same blob of memory, at different offsets. The C Union is the thing that does this, and the union I suggested does that. You seem to also have this idea that you want *exactly the same syntax as well as semantics*. And I don't think there is an answer to that. C has different syntax. You've overconstrained the problem. You need to decide what you really want. – Cheeso Aug 25 '11 at 01:23
  • Maybe what you are asking is, how do I do this in C++ with the managed extensions? and in that case, it's basically the same syntax. See here: http://stackoverflow.com/q/5375370/48082 – Cheeso Aug 25 '11 at 01:27
0

You can do this with a union, perhaps with some #defines to simplify the usage.

union Test {
    struct {
        int V_a;
    } s_a;
    struct {
        char V_a;
        int V_b;
    } S_b;
    struct {
        char V_a;
        short V_b;
        int V_c;
    } S_c;

#define a S_a.V_a
#define b S_b.V_b
#define c S_c.V_c
};
Mark H
  • 13,797
  • 4
  • 31
  • 45
0

Not exactly what you asked for, but you should be able achieve similar effect using bit fields.

Also, for Visual C++, it might be worth looking at: __declspec(align(#)) or #pragma pack.

Branko Dimitrijevic
  • 50,809
  • 10
  • 93
  • 167
  • Would bit fields treat the integers as 4 bytes or 1 byte? – user541686 Aug 25 '11 at 01:16
  • @Mehrdad They will be treated as wide as they were declared. For example if you have an `unsigned int x : 3`, and try to assign 8 to it, the field will actually become 0 because of the wrap-around (3 bits can represent numbers from 0 to 7). There is nothing, however, stopping you from declaring fields as `: 8` or `: 32` bits wide (for 1 and 4 bytes respectively). You can also wrap bit fields in unions, or manipulate them at the bit level, so you can implement pretty much any behavior imaginable... – Branko Dimitrijevic Aug 25 '11 at 10:08
0

Alternative to using the union is to instead use methods to access the values, as you probably should be doing anyway. Although it's C++, where you asked for C - but I'm assuming C++ is fine based on your use of VC++.

#ifdef __cplusplus
struct Test {
    int a() {
        return *(int*)&values_[0];
    }
    void a(int value) {
        *(int*)&values_[1] = value;
    }
    int b() {
        return *(int*)&values_[1];
    }
    void b(int value) {
        *(int*)&values_[1] = value;
    }
    int c() {
        return *(int*)&values_[3];
    }
    void c(int value) {
        *(int*)&values_[3] = value;
    }

private:
    char[8] values_;
};
#endif
Mark H
  • 13,797
  • 4
  • 31
  • 45
  • 1
    I never fully understood the subject but doesn't this violate strict aliasing rules? – Jeff Mercado Aug 25 '11 at 01:34
  • It does, but unimportant for the topic of the question, since he wasn't concerned about portability etc. If you wanted it to be a bit cleaner, you'd replace those dereferences with bit shifting operators to set each byte individually, (at the cost of performance, though, probably negligible.) – Mark H Aug 25 '11 at 01:39