Why does order matter with this if else if statement?

if((row1 = mysql_fetch_row(result1)) && adding_to_member_flag != 1)
{
    printf("Do not update date since it already exists\n");

}
else if(!(row1 = mysql_fetch_row(result1)) && adding_to_member_flag != 1)
{
    printf("Update end_date and add new team\n");
}

When I had it like this the "Do not update date since it already exists" never got printed.

if(!(row1 = mysql_fetch_row(result1)) && adding_to_member_flag != 1)
{
    printf("Update end_date and add new team\n");
}
else if((row1 = mysql_fetch_row(result1)) && adding_to_member_flag != 1)
{
    printf("Do not update date since it already exists\n");

}

Recommended Answers

All 11 Replies

Try again but clarify the second half of the if. What if your compiler thinks you mean "!(row1 = mysql_fetch_row(result1)) && adding_to_member_flag" is not equal to 1?

Don't be afraid to clearly state what you meant.

For starters, you are using dangerous obsolete code that has been completetly removed from Php. You need to use PDO. Click Here

Second, that "code" is not going to do anything. You dont even have variables where you should have them.

Additionally, the "logic" just makes no sense at all.

Like this?

if(!(row1 = mysql_fetch_row(result1)) && (adding_to_member_flag != 1))
{
}

This is C programming not PHP.

C, even better. I see you cleaned up the code to clearly state what you mean.

Now it's time to print those tests to the screen (debugging HO!)

I don't know the full code base but let's check a thing. In your reply above "Like this?" tell me if the mysql_fetch_row supplies or changes the value adding_to_member_flag. Why it matters is that your compiler may do that test first as it is low cost.

If you want to assure that mysql_fetch_row executes before the test of adding_to_member_flag, be sure each test is on it's own if. Like this:
`

  if(!(row1 = mysql_fetch_row(result1)))
        if (adding_to_member_flag != 1)
        {
        }`

What if your compiler thinks you mean ...
Why it matters is that your compiler may do that test first as it is low cost.

I hate to be a pedant here, but the C language clearly defines the priority of operators, and if your compiler does something different then it's not a C compiler. The expression after && is NEVER executed if the expression before it is false.

https://msdn.microsoft.com/en-us/library/2bxt6kc4.aspx?f=255&MSPPError=-2147217396
https://msdn.microsoft.com/en-us/library/z68fx2f1.aspx?f=255&MSPPError=-2147217396

Chucking in lots of redundant parens just makes the code harder to read and will confuse people because it looks like you are trying to override the standard behaviour.

@James,
No I get that. We may be missing the whole animal. Nod to blind men and the elephant.

Can you find docs about what happens if the expression on the left changes the value that is on the right? For me I found that to fail decades ago so I never code a line like that. I'll break it up like I did above or go ahead and perform the action so when I if, the values under test are known.

As to counting on correct C compilers, you are right but then again I was never given a choice long ago. If we found a problem, we would test to see what's up, then code so it works. Some would get upset about that.

I don't disagree, but it's a while since I've had a decent techy chat, so I'll keep going.... :)

IMHO it's essential to understand how the language is defined when faced with a confusing code construct. Just getting one or two test cases to work may fix the immediate problem, but can result in a false understanding of what's really happening.

eg

Can you find docs about what happens if the expression on the left changes the value that is on the right?

This from MS's reference site... "The operands of logical-AND and logical-OR expressions are evaluated from left to right. If the value of the first operand is sufficient to determine the result of the operation, the second operand is not evaluated. ... There is a sequence point after the first operand."
So the expression on the left is executed. The sequence point means that all results and side effects are completed before moving on. Then the RHS is or is not executed, based on the LHS value. No confusion or ambiguity that I can detect there!

Having said that, given that the next person working on your code may be less experienced, I would favour splitting stuff up (and using good names for any intermediate variables that may introduce) to make it absolutely clear. I objected to adding nested parens because IMHO they reduce clarity, not enhance it.

@C

While we can go over C and if's, the code isn't clear to me. I continue to think of 3 blind men describing the elephant.

What if adding_to_member_flag is 1? Nothing will print. Maybe that flag is retrieved from the database? I can't know that.

The code seems clear to me. How C interprets the code seems clear to me. I (think I) understand what the OP's results are when experimenting with the code. I for one would not expect the two code snippets to act identically since I expect mysql_fetch_row to change things every time it is called. From a C standpoint, I can design all sorts of programs where changing the order of the if-tests would have different results. Consider the one below (and I could write many others)...

#include <stdio.h>

int row1, adding_to_member_flag, result1;

int mysql_fetch_row(int x)
{
    printf("mysql_fetch_row called\n");
    static int numTimesCalled = 0;
    adding_to_member_flag = numTimesCalled;
    numTimesCalled++;
    return 1;
}

void foo1()
{
    printf("foo1 called\n");
    if((row1 = mysql_fetch_row(result1)) && adding_to_member_flag != 1)
    {
        printf("Do not update date since it already exists\n");
    }
    else if(!(row1 = mysql_fetch_row(result1)) && adding_to_member_flag != 1)
    {
        printf("Update end_date and add new team\n");
    }
}

void foo2()
{
    printf("foo2 called\n");

    if(!(row1 = mysql_fetch_row(result1)) && adding_to_member_flag != 1)
    {
        printf("Update end_date and add new team\n");

    else if((row1 = mysql_fetch_row(result1)) && adding_to_member_flag != 1)
    {
        printf("Do not update date since it already exists\n");
    }
}

int main()
{
    adding_to_member_flag = 1;
    int choice;
    printf("Enter 1 to run foo1, 2 to run foo2: ");
    scanf("%d", &choice);
    if(choice == 1)
    {
        foo1();
    }
    else if(choice == 2)
    {
        foo2();
    }
    return 0;
}

In this code, result1's value is irrelevent. The function always returns 1, row1 equals 1 for all tests, and so is non-negative, so when row is before the &&, the first test passes. When !row is before the &&, the first test fails. A bit of inspection and substitution changes foo1 and foo2 to this...

void foo1()
{
    printf("foo1 called\n");
    if(TRUE && adding_to_member_flag != 1)
    {
        printf("Do not update date since it already exists\n");
    }
    else if(FALSE && adding_to_member_flag != 1)
    {
        printf("Update end_date and add new team\n");
    }
}

void foo2()
{
    printf("foo2 called\n");

    if(FALSE && adding_to_member_flag != 1)
    {
        printf("Update end_date and add new team\n");
    }
    else if(TRUE && adding_to_member_flag != 1)
    {
        printf("Do not update date since it already exists\n");
    }
}

adding_to_member_flag will be 0 the first time it is called and 1 the second time it is called, so...

void foo1()
{
    printf("foo1 called\n");
    if(TRUE && 0 != 1)
    {
        printf("Do not update date since it already exists\n");
    }
    else if(FALSE && 1 != 1)
    {
        printf("Update end_date and add new team\n");
    }
}

void foo2()
{
    printf("foo2 called\n");

    if(FALSE && 0 != 1)
    {
        printf("Update end_date and add new team\n");
    }
    else if(TRUE && 1 != 1)
    {
        printf("Do not update date since it already exists\n");
    }
}

and then...

void foo1()
{
    printf("foo1 called\n");
    if(TRUE && TRUE)
    {
        printf("Do not update date since it already exists\n");
    }
    else if(FALSE && FALSE)
    {
        printf("Update end_date and add new team\n");
    }
}

void foo2()
{
    printf("foo2 called\n");

    if(FALSE && TRUE)
    {
        printf("Update end_date and add new team\n");
    }
    else if(TRUE && FALSE)
    {
        printf("Do not update date since it already exists\n");
    }
}

I could go on and implement the short-circuiting that James mentioned (and you should to get a better feel for things), but hopefully the above is enough to see what is happening. Keep in mind that the program allows foo1 or foo2 to be called, not both, and only once. The above "code" and analysis requires that rule.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.