Assuming I have a structure such as:
typedef struct
{
char * string1;
char * string2;
} TWO_WORDS;
such that all the fields are of the same type, and my main has
TWO_WORDS tw;
can I reference string1 with tw[0] and string2 with two[1]? If so:
No, you cannot use index access to struct data members, unless you take specific steps to emulate it.
In C++ this functionality can be emulated by using a C++-specific pointer type known as "pointer-to-data-member". C language has no such type, but it can in turn be emulated by using the standard offsetof
macro and pointer arithmetic.
In you example it might look as follows. First, we prepare a special offset array
const size_t TW_OFFSETS[] =
{ offsetof(TWO_WORDS, string1), offsetof(TWO_WORDS, string2) };
This offset array is later used to organize index access to struct members
*(char **)((char *) &tw + TW_OFFSETS[i]);
/* Provides lvalue access to either `tw.string1` or `tw.string2` depending on
the value of `i` */
It doesn't look pretty (although it can be made to look better by using macros), but that's the way it is in C.
For example, we can define
#define TW_MEMBER(T, t, i) *(T *)((char *) &(t) + TW_OFFSETS[i])
and use it in the code as
TW_MEMBER(char *, tw, 0) = "Hello";
TW_MEMBER(char *, tw, 1) = "World";
for (int i = 0; i < 2; ++i)
printf("%s\n", TW_MEMBER(char *, tw, i));
Note that this approach is free from the serious issues present in the solution based on reinterpreting the struct as char*[2]
array (regradless of whether it is done through a union or through a cast). The latter is a hack, illegal from the formal point of view and generally invalid. The offsetof
-based solution is perfectly valid and legal.
can I reference string1 with tw[0] and string2 with two[1]?
No you cannot in C, tw
is a structure not a pointer.
The constraints of the []
operator require one of the operand to be of a pointer type.
To access string1
, you can use this expression: tw.string1
I got pretty close with this construct:
((char**)&tw)[0];
As an example:
int main()
{
typedef struct
{
char * string1;
char * string2;
} TWO_WORDS;
TWO_WORDS tw = {"Hello", "World"};
printf("String1: %s\n", ((char**)&tw)[0]);
printf("String2: %s\n", ((char**)&tw)[1]);
return 0;
}
It is not guaranteed to work, as the compiler may add padding between fields. (Many compilers have a #pragma
that will avoid padding of structs)
To answer each of your questions:
is this part of the c standard? NO
do i have to cast the struct to an array first? YES
what about fields which are different sizes in memory
This can be done with even more "evil" casting and pointer-math
what about fields which are different types but the same size?
This can be done with even more "evil" casting and pointer-math
can you do pointer arithmetic within a structure?
Yes (not guaranteed to always work as you might expect, but a structure is just a piece of memory that you can access with pointers and pointer-math)
As @ouah points out, no you can't do it quite that way. However, you could:
typedef union
{ char *a[2];
struct
{ char *string1;
char *string2;
} s;
} TWO_WORDS;
TWO_WORDS t;
t.a[0] = ...;
t.a[1] = ...;
t.s.string1 = ...;
t.s.string2 = ...;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With