How can I access structure fields by name at run time? - c

The C faqs explain it in a way, here is the link.
But I can't understand it, Somebody can explain it for me? Or give me another way?
Thanks so much!

I think this example makes the answer clear:
struct test
{
int b;
int a;
};
int main()
{
test t;
test* structp = &t;
//Find the byte offset of 'a' within the structure
int offsetf = offsetof(test, a);
//Set the value of 'a' using pointer arithmetic
*(int *)((char *)structp + offsetf) = 5;
return 0;
}

You can't, not without implementing some kind of name lookup yourself.
C doesn't have any time of name information left when the program is running.
Supporting this generally for different struct field types is complicated.

If you have your binary compiled with debug information, you can use it to lookup names at runtime. For example gcc (typically) produces debug info in DWARF format, and you can use libdwarf to process it.
In case of DWARF you can find your field in DW_TAG_member node, DW_AT_data_member_location attribute will give you the field's offset, same as you get from offsetof() at compile time.

If a structure is defined using a struct {...} definition, it is unlikely that there will be any information in the executable code related to member names. Some platforms build "debug" information into generated executable files, and there may be some means by which a running program could retrieve that information, but there's no common way to do such things.
What one may be able to do, however, is use macros to define a structure. For example, one could define:
#define MAKE_ACME_STRUCT \
FIELD(id,int,23) \
X FIELD(name,char30,"Untitled") \
X FIELD(info,int,19) \
// LEAVE THIS COMMENT HERE
and then invoke the MAKE_ACME_STRUCT macro various times, with the FIELD and X macros defined different ways, so that it would expand either to a struct statement, or an initialization expression for a "default" instance of that struct, or as an initialization expression for an array of items describing the struct fields [e.g. something like
STRUCT_INFO acme_struct_info[] = {
{"id", STRUCT_INFO_TYPE_int, sizeof(ACME_STRUCT.id), offsetof(ACME_STRUCT.id)}
,{"name", STRUCT_INFO_TYPE_char30, sizeof(ACME_STRUCT.name), offsetof(ACME_STRUCT.name)}
,{"info", STRUCT_INFO_TYPE_int, sizeof(ACME_STRUCT.info), offsetof(ACME_STRUCT.info)}
,{0}};
It would be necessary that all types used within the struct have single-token names, and that for each such name, an identifier STRUCT_INFO_TYPE_nameGoesHere be defined which identifies the type to a run-time library in some form that it understands.
Such macros are hardly beautiful, but they have the advantage of ensuring that all the things they're used to define remain in sync [e.g. ensuring that adding or removing an element of acme_struct will cause it to be added or removed from the list of struct members stored in acme_struct_info].

Keep track of the field offsets as computed using the offsetof() macro. If structp is a pointer to an instance of the structure, and field f is an int having offset offsetf, f's value can be set indirectly with
*(int *)((char *)structp + offsetf) = value;

Related

Using different struct definitions to simulate public and private fields in C

I have been writing C for a decent amount of time, and obviously am aware that C does not have any support for explicit private and public fields within structs. However, I (believe) I have found a relatively clean method of implementing this without the use of any macros or voodoo, and I am looking to gain more insight into possible issues I may have overlooked.
The folder structure isn't all that important here but I'll list it anyway because it gives clarity as to the import names (and is also what CLion generates for me).
- example-project
- cmake-build-debug
- example-lib-name
- include
- example-lib-name
- example-header-file.h
- src
- example-lib-name
- example-source-file.c
- CMakeLists.txt
- CMakeLists.txt
- main.c
Let's say that example-header-file.h contains:
typedef struct ExampleStruct {
int data;
} ExampleStruct;
ExampleStruct* new_example_struct(int, double);
which just contains a definition for a struct and a function that returns a pointer to an ExampleStruct.
Obviously, now if I import ExampleStruct into another file, such as main.c, I will be able to create and return a pointer to an ExampleStruct by calling
ExampleStruct* new_struct = new_example_struct(<int>, <double>);,
and will be able to access the data property like: new_struct->data.
However, what if I also want private properties in this struct. For example, if I am creating a data structure, I don't want it to be easy to modify the internals of it. I.e. if I've implemented a vector struct with a length property that describes the current number of elements in the vector, I wouldn't want for people to just be able to change that value easily.
So, back to our example struct, let's assume we also want a double field in the struct, that describes some part of internal state that we want to make 'private'.
In our implementation file (example-source-file.c), let's say we have the following code:
#include <stdlib.h>
#include <stdbool.h>
typedef struct ExampleStruct {
int data;
double val;
} ExampleStruct;
ExampleStruct* new_example_struct(int data, double val) {
ExampleStruct* new_example_struct = malloc(sizeof(ExampleStruct));
example_struct->data=data;
example_struct->val=val;
return new_example_struct;
}
double get_val(ExampleStruct* e) {
return e->val;
}
This file simply implements that constructor method for getting a new pointer to an ExampleStruct that was defined in the header file. However, this file also defines its own version of ExampleStruct, that has a new member field not present in the header file's definition: double val, as well as a getter which gets that value. Now, if I import the same header file into main.c, which contains:
#include <stdio.h>
#include "example-lib-name/example-header-file.h"
int main() {
printf("Hello, World!\n");
ExampleStruct* test = new_example(6, 7.2);
printf("%d\n", test->data); // <-- THIS WORKS
double x = get_val(test); // <-- THIS AND THE LINE BELOW ALSO WORK
printf("%f\n", x); //
// printf("%f\n", test->val); <-- WOULD THROW ERROR `val not present on struct!`
return 0;
}
I tested this a couple times with some different fields and have come to the conclusion that modifying this 'private' field, val, or even accessing it without the getter, would be very difficult without using pointer arithmetic dark magic, and that is the whole point.
Some things I see that may be cause for concern:
This may make code less readable in the eyes of some, but my IDE has arrow buttons that take me to and from the definition and the implementation, and even without that, a one line comment would provide more than enough documentation to point someone in the direction of where the file is.
Questions I'd like answers on:
Are there significant performance penalties I may suffer as a result of writing code this way?
Am I overlooking something that may make this whole ordeal pointless, i.e. is there a simpler way to do this or is this explicitly discouraged, and if so, what are the objective reasons behind it.
Aside: I am not trying to make C into C++, and generally favor the way C does things, but sometimes I really want some encapsulation of data.
Am I overlooking something that may make this whole ordeal pointless, i.e. is there a simpler way to do this or is this explicitly discouraged, and if so, what are the objective reasons behind it.
Yes: your approach produces undefined behavior.
C requires that
All declarations that refer to the same object or function shall have compatible type; otherwise, the behavior is undefined.
(C17 6.2.7/2)
and that
An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
a type compatible with the effective type of the object,
a qualified version of a type compatible with the effective type of the object,
[...]
an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a
subaggregate or contained union), or
a character type.
(C17 6.5/7, a.k.a. the "Strict Aliasing Rule")
Your two definitions of struct ExampleStruct define incompatible types because they specify different numbers of members (see C17 6.2.7/1 for more details on structure type compatibility). You will definitely have problems if you pass instances by value between functions relying on different of these incompatible definitions. You will have trouble if you construct arrays of them, whether dynamically, automatically, or statically, and attempt to use those across boundaries between TUs using one definition and those using another. You may have problems even if you do none of the above, because the compiler may behave unexpectedly, especially when optimizing. DO NOT DO THIS.
Other alternatives:
Opaque pointers. This means you do not provide any definition of struct ExampleStruct in those TUs where you want to hide any of its members. That does not prevent declaring and using pointers to such a structure, but it does prevent accessing any members, declaring new instances, or passing or receiving instances by value. Where member access is needed from TUs that do not have the structure definition, it would need to be mediated by accessor functions.
Just don't access the "private" members. Do not document them in the public documentation, and if you like, explicity mark them (in code comments, for example) as reserved. This approach will be familiar to many C programmers, as it is used a lot for structures declared in POSIX system headers.
As long as the public has a complete definition for ExampleStruct, it can make code like:
ExampleStruct a = *new_example_struct(42, 1.234);
Then the below will certainly fail.
printf("%g\n", get_val(&a));
I recommend instead to create an opaque pointer and provide access public functions to the info in .data and .val.
Think of how we use FILE. FILE *f = fopen(...) and then fread(..., f), fseek(f, ...), ftell(f) and eventually fclose(f). I suggest this model instead. (Even if in some implementations FILE* is not opaque.)
Are there significant performance penalties I may suffer as a result of writing code this way?
Probably:
Heap allocation is expensive, and - today - usually not optimized away even when that is theoretically possible.
Dereferencing a pointer for member access is expensive; although this might get optimized away with link-time-optimization... if you're lucky.
i.e. is there a simpler way to do this
Well, you could use a slack array of the same size as your private fields, and then you wouldn't need to go through pointers all the time:
#define EXAMPLE_STRUCT_PRIVATE_DATA_SIZE sizeof(double)
typedef struct ExampleStruct {
int data;
_Alignas(max_align_t) private_data[EXAMPLE_STRUCT_PRIVATE_DATA_SIZE];
} ExampleStruct;
This is basically a type-erasure of the private data without hiding the fact that it exists. Now, it's true that someone can overwrite the contents of this array, but it's kind of useless to do it intentionally when you "don't know" what the data means. Also, the private data in the "real" definition will need to have the same, maximal, _AlignAs() as well (if you want the private data not to need to use AlignAs(), you will need to use the real alignment quantum for the type-erased version).
The above is C11. You can sort of do about the same thing by typedef'ing max_align_t yourself, then using an array of max_align_t elements for private data, with an appropriate length to cover the actual size of the private data.
An example of the use of such an approach can be found in CUDA's driver API:
Parameters for copying a 3D array: CUDA_MEMCPY3D vs
Parameters for copying a 3D array between two GPU devices: CUDA_MEMCPY3D_peer
The first structure has a pair of reserved void* fields, hiding the fact that it's really the second structure. They could have used an unsigned char array, but it so happens that the private fields are pointer-sized, and void* is also kind of opaque.
This causes undefined behaviour, as detailed in the other answers. The usual way around this is to make a nested struct.
In example.h, one defines the public-facing elements. struct example is not meant to be instantiated; in a sense, it is abstract. Only pointers that are obtained from one of it's (in this case, the) constructor are valid.
struct example { int data; };
struct example *new_example(int, double);
double example_val(struct example *e);
and in example.c, instead of re-defining struct example, one has a nested struct private_example. (Such that they are related by composite aggregation.)
#include <stdlib.h>
#include "example.h"
struct private_example {
struct example public;
double val;
};
struct example *new_example(int data, double val) {
struct private_example *const example = malloc(sizeof *example);
if(!example) return 0;
example->public.data = data;
example->val = val;
return &example->public;
}
/** This is a poor version of `container_of`. */
static struct private_example *example_upcast(struct example *example) {
return (struct private_example *)(void *)
((char *)example - offsetof(struct private_example, public));
}
double example_val(struct example *e) {
return example_upcast(e)->val;
}
Then one can use the object as in main.c. This is used frequently in linux kernel code for container abstraction. Note that offsetof(struct private_example, public) is zero, ergo example_upcast does nothing and a cast is sufficient: ((struct private_example *)e)->val. If one builds structures in a way that always allows casting, one is limited by single inheritance.

Beginner: Pointers and General Syntax in C Programming

Can someone please help me understand what this is doing:
alt_up_sd_card_dev *dev = (alt_up_sd_card_dev *) alt_find_dev(name, &alt_dev_list);
if (dev != NULL)
{
aux_status_register = ((short int *) SD_CARD_AUX_STATUS(dev->base));
}
I understand that the (short int *) is "type-casting" (as explained to me by some other helpful people on this forum) what SD_CARD_AUX_STATUS should be when the contents are called, but I've never seen the dev->base syntax before....
1.Here dev, is structure pointer. This pointer gets the memory from this line (alt_up_sd_card_dev *) alt_find_dev(name, &alt_dev_list);
2.The structure alt_up_sd_card_dev may have member called base.
3.SD_CARD_AUX_STATUS could be macro, which does some manipulation on dev->base pointer.
For more information, check the parameterised MACRO concepts in C
We can't give you a proper answer without knowing all the include files this references, but by general convention:
1) By standard C naming conventions, the all-uppercase SD_CARD_AUX_STATUS() is a macro rather than a function. The macro is set up by a #define either earlier in this file or in one of the #included .h files. Look for that definition to find out what it's actually doing.
2) -> is like . but for pointers-to-structures rather than structures. That is, if you have a struct { int foo, bar; } baz, then baz.foo is the same thing as (&baz)->foo Or, as Wikipedia puts it:
Structure dereference ("member b of object pointed to by a") a->b
Structure reference ("member b of object a") a.b
This is not related to C syntax in general. This piece of code is very specific.
I can only guess what it does.
alt_up_sd_card_dev *dev = (alt_up_sd_card_dev *) alt_find_dev(name, &alt_dev_list);
This calls a function alt_find_dev which probably looks for a device. The device is apparently an sd card reader... The result of the function is cast to a specific type of pointer. Probably the result is of generic pointer type and it is cast to a pointer to a structure that describes specifically an sd card device. It is then stored in the dev variable.
if (dev != NULL)
if the device is found....
aux_status_register = ((short int *) SD_CARD_AUX_STATUS(dev->base));
a macro SD_CARD_AUX_STATUS is called with a parameter dev->base (where base is a field in the structure describing the sd card device). The operator -> is called pointer dereference and it is simillar to . operator. It allows to access fields of a struct which is pointed by the pointer. The macro returns some kind of a status of the device. Hard to tell why it is cast to a pointer to short int, but the result is stored in a variable aux_status_register.
Without additional information it's impossible to tell anything more about the code.
dev is a pointer to a data structure in memory - called a struct in C. A struct has members - a set of variables within it. dev->base means access the member called base within the struct of type alt_up_sd_card_dev which dev is pointing to.
Look for the definition of struct alt_up_sd_card_dev which you will find in one of the header files included from the one you are looking at.
In general the -> operator is said to de-reference the pointer.
SD_CARD_AUX_STATUS is probably a macro - traditionally these are named all upper case. It might perform some kind of conversion or even call a function. Search for its definition in the headers.

What data type needed to receive value from this function?

I need help figuring out the correct data type for an assignment from a function call please.
I'm trying to get at the data in the content field of N_Vector u. Here's what the documentation says about N_Vector:
The type N_Vector is defined as
N_Vector u;
tpedef struct _generic_N_Vector *N_Vector;
struct _generic_N_Vector {
void *content;
struct _generic_N_Vector_Ops *ops;
};
...
[The parallel NVECTOR module] defines the content field of N_Vector
to be a structure containing global and local lengths, a pointer to the
beginning of contiguous local data array, MPI communicator and flag.
struct _N_VectorContent_Parallel {
long int local_length;
long int global_length;
booleantype own_data;
realtype *data;
MPI_Comm comm;
}
So I guess that means that content in _generic_N_Vector "points to" a structure of type _N_VectorContent_Parallel (right?).
Then I try to use a macro for accessing content. Here's the documentation for NV_CONTENT_P.
v_cont=NV_CONTENT_P(v) sets v_cont to be a pointer to the N_Vector content
structure of type struct _N_VectorParallelContent.
Notice the different name of the struct!
What does that mean? What type do I declare v_cont to be?
I tried
N_Vector u;
...
_N_VectorParallelContent *v_cont1;
_N_VectorContent_Parallel *v_cont2;
v_cont1 = NV_CONTENT_P(u);
v_cont2 = NV_CONTENT_P(u);
but these declarations got the error "'_N_VectorContent_Parallel' undeclared..." or "'_N_VectorParallelContent' undeclared...".
But it seems that these structures must be delcared already. I successfully declared (and used) u, of type N_Vector. And the docs seem to say that N_Vector contains one of those two structures (or maybe both).
So why the error message? What is the correct data type to declare for v_cont to receive data from NV_CONTENT_P?
I know this is a long, detailed question, but I don't understand enough to whittle it down any more.
Thanks for your help.
I'm not familiar with this particular library, but it looks to me like the documentation is a little inconsistent.
Right after the blurb about NV_CONTENT_P(v), it says NV_CONTENT_P(v) is defined as:
#define NV_CONTENT_P(v) ( (N_VectorContent_Parallel)(v->content) )
So that version of the name is probably correct. I can't see a definition for N_VectorContent_Parallel on that page, but it's probably defined somewhere as something like struct _N_VectorContent_Parallel*. So, you can probably do:
N_VectorContent_Parallel v_cont1 = NV_CONTENT_P(u);
Remember that for structs, struct is part of the type name. This means that you're getting errors in your example because you haven't included struct:
// this is an unknown type
_N_VectorParallelContent *v_cont1;
// this is a "struct _N_VectorParallelContent"
struct _N_VectorParallelContent *v_cont1;
// But use this one, as it follows the macro
N_VectorContent_Parallel v_cont1;
If you want to see exactly what the preprocessor has done to your code, you can use gcc's -E flag.
-E Stop after the preprocessing stage; do not run the compiler proper.
The output is in the form of preprocessed source code, which is sent to
the standard output.
Input files which don't require preprocessing are ignored.
This is especially useful for seeing the results of macros and multiple complex header files.
Edit: From the source you've linked:
typedef struct _N_VectorContent_Parallel *N_VectorContent_Parallel;
This is a type definition that says that N_VectorContent_Parallel is the same as a struct _N_VectorContent_Parallel * (a pointer to a struct _N_VectorContent_Parallel), which means you can access v_cont1 using the -> syntax:
N_VectorContent_Parallel v_cont1;
printf("%d",v_cont1->local_length);
a->b is is shorthand for (*a).b - it's just a cleaner-looking way of writing the dereference needed to accessing a member of a struct through a pointer to that struct. If that seems confusing, see my answer to this question.
Personally, I don't like typedefs that hide pointers like this one, because it's hard to tell by looking at the code whether you need to use a.b or a->b.

Access struct members as if they are a single array?

I have two structures, with values that should compute a pondered average, like this simplified version:
typedef struct
{
int v_move, v_read, v_suck, v_flush, v_nop, v_call;
} values;
typedef struct
{
int qtt_move, qtt_read, qtt_suck, qtd_flush, qtd_nop, qtt_call;
} quantities;
And then I use them to calculate:
average = v_move*qtt_move + v_read*qtt_read + v_suck*qtt_suck + v_flush*qtd_flush + v_nop*qtd_nop + v_call*qtt_call;
Every now and them I need to include another variable. Now, for instance, I need to include v_clean and qtt_clean. I can't change the structures to arrays:
typedef struct
{
int v[6];
} values;
typedef struct
{
int qtt[6];
} quantities;
That would simplify a lot my work, but they are part of an API that need the variable names to be clear.
So, I'm looking for a way to access the members of that structures, maybe using sizeof(), so I can treat them as an array, but still keep the API unchangeable. It is guaranteed that all values are int, but I can't guarantee the size of an int.
Writing the question came to my mind... Can a union do the job? Is there another clever way to automatize the task of adding another member?
Thanks,
Beco
What you are trying to do is not possible to do in any elegant way. It is not possible to reliably access consecutive struct members as an array. The currently accepted answer is a hack, not a solution.
The proper solution would be to switch to an array, regardless of how much work it is going to require. If you use enum constants for array indexing (as #digEmAll suggested in his now-deleted answer), the names and the code will be as clear as what you have now.
If you still don't want to or can't switch to an array, the only more-or-less acceptable way to do what you are trying to do is to create an "index-array" or "map-array" (see below). C++ has a dedicated language feature that helps one to implement it elegantly - pointers-to-members. In C you are forced to emulate that C++ feature using offsetof macro
static const size_t values_offsets[] = {
offsetof(values, v_move),
offsetof(values, v_read),
offsetof(values, v_suck),
/* and so on */
};
static const size_t quantities_offsets[] = {
offsetof(quantities, qtt_move),
offsetof(quantities, qtt_read),
offsetof(quantities, qtt_suck),
/* and so on */
};
And if now you are given
values v;
quantities q;
and index
int i;
you can generate the pointers to individual fields as
int *pvalue = (int *) ((char *) &v + values_offsets[i]);
int *pquantity = (int *) ((char *) &q + quantities_offsets[i]);
*pvalue += *pquantity;
Of course, you can now iterate over i in any way you want. This is also far from being elegant, but at least it bears some degree of reliability and validity, as opposed to any ugly hack. The whole thing can be made to look more elegantly by wrapping the repetitive pieces into appropriately named functions/macros.
If all members a guaranteed to be of type int you can use a pointer to int and increment it:
int *value = &(values.v_move);
int *quantity = &(quantities.qtt_move);
int i;
average = 0;
// although it should work, a good practice many times IMHO is to add a null as the last member in struct and change the condition to quantity[i] != null.
for (i = 0; i < sizeof(quantities) / sizeof(*quantity); i++)
average += values[i] * quantity[i];
(Since the order of members in a struct is guaranteed to be as declared)
Writing the question came to my mind... Can a union do the job? Is there another clever way to automatize the task of adding another member?
Yes, a union can certainly do the job:
union
{
values v; /* As defined by OP */
int array[6];
} u;
You can use a pointer to u.values in your API, and work with u.array in your code.
Personally, I think that all the other answers break the rule of least surprise. When I see a plain struct definition, I assume that the structure will be access using normal access methods. With a union, it's clear that the application will access it in special ways, which prompts me to pay extra attention to the code.
It really sounds as if this should have been an array since the beggining, with accessor methods or macros enabling you to still use pretty names like move, read, etc. However, as you mentioned, this isn't feasible due to API breakage.
The two solutions that come to my mind are:
Use a compiler specific directive to ensure that your struct is packed (and thus, that casting it to an array is safe)
Evil macro black magic.
How about using __attribute__((packed)) if you are using gcc?
So you could declare your structures as:
typedef struct
{
int v_move, v_read, v_suck, v_flush, v_nop, v_call;
} __attribute__((packed)) values;
typedef struct
{
int qtt_move, qtt_read, qtt_suck, qtd_flush, qtd_nop, qtt_call;
} __attribute__((packed)) quantities;
According to the gcc manual, your structures will then use the minimum amount of memory possible for storing the structure, omitting any padding that might have normally been there. The only issue would then be to determine the sizeof(int) on your platform which could be done through either some compiler macros or using <stdint.h>.
One more thing is that there will be a performance penalty for unpacking and re-packing the structure when it needs to be accessed and then stored back into memory. But at least you can be assured then that the layout is consistent, and it could be accessed like an array using a cast to a pointer type like you were wanting (i.e., you won't have to worry about padding messing up the pointer offsets).
Thanks,
Jason
this problem is common, and has been solved in many ways in the past. None of them is completely safe or clean. It depends on your particuar application. Here's a list of possible solutions:
1) You can redefine your structures so fields become array elements, and use macros to map each particular element as if it was a structure field. E.g:
struct values { varray[6]; };
#define v_read varray[1]
The disadvantage of this approach is that most debuggers don't understand macros. Another problem is that in theory a compiler could choose a different alignment for the original structure and the redefined one, so the binary compatibility is not guaranted.
2) Count on the compiler's behaviour and treat all the fields as it they were array fields (oops, while I was writing this, someone else wrote the same - +1 for him)
3) create a static array of element offsets (initialized at startup) and use them to "map" the elements. It's quite tricky, and not so fast, but has the advantage that it's independent of the actual disposition of the field in the structure. Example (incomplete, just for clarification):
int positions[10];
position[0] = ((char *)(&((values*)NULL)->v_move)-(char *)NULL);
position[1] = ((char *)(&((values*)NULL)->v_read)-(char *)NULL);
//...
values *v = ...;
int vread;
vread = *(int *)(((char *)v)+position[1]);
Ok, not at all simple. Macros like "offsetof" may help in this case.

Struct that apparently defines no instances in Unix v6

I'm going through the code of Unix version 6 with the Lion's book. One of the header files (param.h, can be accessed here) defines the following structs:
/*struct to access integers*/
/*single integer */
struct { int integ; };
/*in bytes*/
struct { char lobyte; char hibyte; };
These structures don't seem to define any instance, nor are they named so they can be used later. Does anybody know what is their use?
Thanks
If someone included the whole file in a union declaration, it would allow them to access the different parts.
It would be something like:
union{
#include <param.h>
} myparam;
myparam.integ = 0xDEAD;
assert(myparam.lobyte == 0xAD)
assert(myparam.hibyte == 0xDE)
(Depends on endianness of architecture...)
So having looked around a bit, it seems that in old versions of C, you wouldn't have needed to declare the union ; there was only one namespace for all struct/union members that just translated into a byte offset that you could use on any variable. The best mention of this I could find is here :
http://docs.sun.com/source/806-3567/compat.html
Describing pre-ISO Sun C:
Allows struct, union, and arithmetic types using member selection operators ('.', '->') to work on members of other struct(s) or unions.
Back in those days, the members of structures all shared the same namespace, not one namespace per structure. Consequently, each element of a structure had to have a unique name across all structures, or the same element had to appear with the same type at the same offset in every structure in which it appeared. Quite how that was used with these, I'm not sure, but I suspect you could do:
int x;
x.lobyte = 1;
x.hibyte = 2;
Or something analogous to that.
See also:
http://www.cs.bell-labs.com/who/dmr/chist.html
http://www.cs.bell-labs.com/who/dmr/primevalC.html
(Neither of those seems to answer this question, though.)

Resources