views:

257

answers:

4
while (curr_data[1] != (unsigned int)NULL &&
    ((curr_ptr = (void*)curr_data[1]) || 1))

Two part question.

What will (curr_ptr = (void*)curr_data[1]) evaluate to, logically. TRUE?

Also, I know its rather hack-ish, but is the while statement legal C? I would have to go through great contortions to put the assignment elsewhere in the code, so I'd be really nice if I could leave it there, but if it's so egregious that it makes everyone's eyeballs burst into flames, I'll change it.

+3  A: 

(curr_ptr = (void*)curr_data[1]) will evaluate to TRUE unless it is a null pointer.

Assuming that curr_data is an array of pointers, and what you want to do is to run the loop while the second of these pointers is not null, while assigning its value to curr_ptr, I would do:

while ((curr_ptr = (void*)curr_data[1]) != NULL) { ... }
Konamiman
Oh, so my initial check is redundant, then? My initial check is to see if `curr_data[1]` contains null, but you're saying this would do the same thing?
Andy Shulman
caf
+2  A: 

To answer your questions:

  1. It will evaluate to true if curr_ptr isn't set to NULL (i.e. curr_data[1] isn't 0).
  2. I believe it's legal, but there are bigger problems with this line of code.

Anyway, I'm assuming you didn't write this code, because you're debating about leaving it in vs. taking it out. So I want you to find out who wrote this line of code and introduce them to a heavy blunt object.

  1. (unsigned int)NULL is ridiculous. Why would you do this? This will probably be the same as just writing 0 (not sure if that's guaranteed by the standard).
  2. What kind of data is in curr_data[1] if it's being cast to a pointer (and pointers are being cast to it)? If it's supposed to be holding a pointer as an integral type, you should use the type intptr_t or uintptr_t provided in <stdint.h> for that purpose (if you're compiler doesn't support C99 ptrdiff_t may be an acceptable substitute).
  3. The || 1 at the end seems to be redundant. If curr_ptr = (void*)curr_data[1] would have evaluated to false, we would have caught that in the first condition.

It may be a pain in the ass, but seriously reconsider rewriting this line. It looks like an entry in the IOCCC.

Chris Lutz
Haha, heavy blunt objects have been applied to this person already in the form of a kick out of the door. Anyway...1. casting `NULL` as an `unsigned int` prevents the warning `warning: assignment makes integer from pointer without a cast`. I just left it in to avoid retyping half the program.2. Good idea. I'll see if I can make that change without breaking too much else.3. Yea, I was wondering about that, especially in light of the first response I got.
Andy Shulman
If you have to do a cast there, cast `curr_data[1]` to a pointer type to better reflect how you're going to use it. However, if it held 0, casting it to a pointer will yield `NULL`, so you can just as easily do `curr_data[1] != 0` or even `curr_data[1]` and have the same logical check. My personal, hopefully more readable rewrite: `while(curr_data[1]) curr_ptr = (void *)curr_data[1];`
Chris Lutz
And the version that works knowing this is part of a `do {} while` loop: `do { ... } while(curr_ptr = (void*)curr_data[1]);` Alternatively, if you need to have a non-trash `curr_ptr` after your loop is over: `do { ... } while(curr_data[1] ` Hopefully that should work.
Chris Lutz
+1  A: 

Assignments are expressions in C, so what you have works. Changing the ; to {} means the exact same thing and is much clearer, do that change at the very least. Assignments in conditions should be avoided when you have a clearer alternative (which is usually true), but if this is clearest in this place, then use it.

The result of an assignment is the assigned-to object. a = value will do the assignment and then evaluate to a. This is used to do things like a = b = 0.

To further clean up the code, there's no need for the void cast, and if this is chars, use '\0' (the null character) instead of NULL (which is supposed to be used with pointers only).

Roger Pate
A: 

You wouldn't have to go through "great contortions", that is completely equivalent to

while (curr_data[1]) {
    curr_ptr = (void *)curr_data[1];
caf
Unfortunately this is part of a do-while loop.
Andy Shulman
@Andy - Aaaaaah! Here we are confronted with the real problem. I was wondering why we were looping to the end without doing any work.
Chris Lutz