views:

333

answers:

8

I have a function, which has a pointer to some structure as its argument. How can I check within this function, whether all required fields of the structure have been filled before a function call?

example:

//lib.c
void f(X_type *x)
{
  ...
}

//user.c
main(){
X_type object;
object.name = "I am X";
object.ID = 1;
...
f(X_type &object);
}
+1  A: 

Use assertions (from assert.h) to check the prerequisites needed by your function. It is up to you to define what is a valid or invalid value for a field of the structure.

example:

assert( NULL != object);
assert( NULL != object->name);
Cătălin Pitiș
Will this not fail because the memory is uninitialized?
Sebastiaan Megens
I have to check if a structure was filled.
Norma
@Sebastiaan: Checking that a piece of memory is initialized or not is tricky. I see no silverbullet on that. The only things that I see feasible is to check prerequisites.
Cătălin Pitiș
NO! it doesn't work. I do not want to check the fields' values. I have to check if they've been set (or some of them depending on the first argument).
Norma
@Norma: unless you have some conventions for each field what it is a valid value and what is not, you can't.
Cătălin Pitiș
You can turn up compiler warnings and catch a lot of (but not all) uses of uninitialized variables.
LnxPrgr3
A: 

Your best bet is to write a function that validates the contents of the struct manually and returns a True/False (however you define it), this way you can easily use the method wherever you utilize this struct.

miko
+1  A: 

Add another member to the structure to indicate if the rest of the members are filled (and initialize it to "false"). Then just check that new member.

struct whatever {
  int datagood;
  /* more members; */
};

struct whatever bar;
bar.datagood = 0;

foo(&bar); /* foo() will see datagood == 0 */

/* bar.a = 42; */
/* bar.b = 24; */
bar.datagood = 1;

foo(&bar); /* foo() will see datagood == 1 */
pmg
What can stop you from occasional initialization of only datagood field?
Dmitriy Matveev
doesn't look like this is a correct interpretation of the problem's expectations. but +1, pmg's suggestion is good for some things like lazy initialization, as in: if (!foo->InitializedBefore) { /* ... */ foo->InitializedBefore = 1; }
asveikau
+3  A: 

Create an initialiser function that takes all the fields as arguments (as if it were an object constructor) and use it instead of setting the fields one by one.

Of course, that won't prevent anybody to keep it doing the wrong way, but if you maintain the discipline of using that function, it will be much more difficult to leave some field uninitialised without noticing. And if you change the fields of the structure (and the function accordingly), the compiler will complain about the mismatching arguments wherever you forgot to update.

You can go a little bit further (but not much more with just plain C) doing some tricks with the preprocessor and the includes to enforce the data encapsulation, but it's somewhat cumbersome. Any book on OOP with C will help you with that issue, but I don't know if the gain is worth the effort.

fortran
doing some tricks with the preprocessor and the includes to enforce the data encapsulation --- can you please explain it?OOP with C will help you with that issue --- which one please? I haven't heard about C and OOP (or you mean C++ ?).
Norma
I mean plain C, but it's not very pleasant to do... take a look to the Glib docs for example, or this book http://www.planetpdf.com/codecuts/pdfs/ooc.pdf
fortran
take a look to this example too: http://en.wikipedia.org/wiki/Opaque_pointer#Cthe bad thing with this approach is that you're bound to use always dynamic memory, but I think there was a way to bypass that by defining and undefining things... let me take a further look.
fortran
+1  A: 

Is valgrind available on your system? If you run your program through it, it will automatically detect the use of any uninitialized variables. It can also catch quite a few other problems (such as using memory that's already been free'd). This won't then become a permanent feature of your program, but it's very nice for debugging.

I would combine this with the asserts mentioned earlier and increased compiler warnings. That's about all you can do—the problem is there's no difference between initialized and uninitialized memory. To the machine, they are all just values.

LnxPrgr3
+1  A: 

I do not think there is a solution in C itself. As others suggested, you may use valgrind, but it is another story. I always memset() the struct:

memset(&object, 0, sizeof(struct mystruct));

or

struct mystruct *p = calloc(1, sizeof(struct mystruct));

Then you can check the members against 0. I believe this is a good habit.

+1 I was wondering for a minute why nobody was mentioning memset()...
asveikau
+1  A: 

By static analysis. Parasoft C++test has BD-PB-NOTINIT (Avoid usage of not initialized data) flowanalysis rule for that.

Dmitriy Matveev
A: 

This is usually solved by careful programming, but if you have to be sure, here's an overkill idea:

  • Add a checksum/crc field.
  • Add an update function of members that also modifies the checksum field.
  • Upon using, use another function to compare the checksum of the fields with that of the checksum field.
Liran Orevi