Используйте ссылки.
C ++:
void foo(stuff_s &what)
{
what.o.s = 4;
}
int main()
{
stuff_s SetToFour;
foo(SetToFour);
}
C:
void foo(stuff_s *what)
{
if (what == NULL) return;
what->o.s = 4;
}
int main(int argc, char *argv[])
{
stuff_s SetToFour;
foo(&SetToFour);
return 0; /* Because it's main in a strict C compiler. Ignore this. */
}
Что касается дизайна вашей программы, если ваши данные действительно, действительно непознаваемыЯ бы рекомендовал использовать указатель void * и тег типа объекта или получить класс из базового класса.
C ++:
class base {
public:
int a;
virtual void do_whatever();
virtual int get_type() = 0; // Grab our type ID
};
class derived : public base {
public:
int b;
float c;
char *d;
virtual void do_whatever() { c = 4.0F; }
virtual int get_type() { return 1; }
};
struct stuff_s {
// ...in o
base *futs;
}
// Later on...
stuff_s foo;
switch (foo.o.futs->get_type()) {
case 0: // Base class
break;
case 1: // Class type 'derived'
derived *a = dynamic_cast<derived *>(foo.o.futs); // Dynamic cast lets us take a pointer to a base type and make it into a pointer to a derived type. Using our tag ID that we get from the virtual function, we can determine exactly which type to do.
a->b = 4;
break;
}
// This is roughly the same amount of code as the C version would use
Если вы действительно хотите, я предоставлюПример C, но он становится слишком длинным
РЕДАКТИРОВАТЬ: я видел ниже, что он должен быть C-совместимым.Поэтому я расширю, чтобы включить эквивалент C этого последнего кода на C, а также включить передачу по ссылке.Имейте в виду, что это концептуально: он будет компилироваться, но он не очень полезен.
C:
/* This is a generic object. It has a type ID and a pointer, that is all that is needed. It can hold anything. */
struct generic_holder {
int type;
void *ptr;
};
/* This is an example struct it may point to. */
struct holder_one {
int a;
int b;
float c;
char *d;
int change_this;
};
/* This is another example struct. */
struct holder_two {
char best[50];
char worst[50];
int change_this;
};
struct stuff_s {
/* ...in .o */
generic_holder data;
};
/* Forward-declaration */
void set_to_four(stuff_s *foo);
/* Later on... */
int main(int argc, char* argv[])
{
stuff_s foo;
holder_two test_struct = { "C++", "Lisp", 0 }; // Best, worst. Haha.
foo.o.data.ptr = (void *)&test_struct; /* This makes it into a "generic pointer" by casting it to void */
foo.o.data.type = 2; /* = 2 because we are using holder_two */
/* We're going to use our function to set data in a generic object, passing by reference. This would work equally well on something of type holder_one, and can be expanded for data types you haven't thought of. */
set_to_four(&foo);
return 0;
}
/* This function will take a generic object and set the 'change_this' variable to 4 */
void set_to_four(stuff_s *foo)
{
holder_one *ptr1;
holder_two *ptr2;
if (foo == NULL) return; /* Obsessively check for invalid pointers */
assert(foo.o.data.ptr != NULL); /* Some people prefer to do checks only in debug, for speed. This does the same thing but only if debug is on. And it stops the program when it gets there if there is an error. It evaluates to nothing if it's a release build. */
switch(foo.o.data.type) {
case 1:
ptr1 = (holder_one *)foo.o.data.ptr;
ptr1->change_this = 4;
break;
case 2:
ptr2 = (holder_two *)foo.o.data.ptr;
ptr2->change_this = 4;
break;
default:
break;
}
}