Am I doing something wrong with printf() here?

E

Eric Lilja

Hello, I have two code snippets I want you to look at. My program compiles
without warnings (warning level set to max, gcc 3.4.3) with either snippet
but the latter one causes a segfault at run-time. I know it contains
non-standard constructs (using the MySql C api) but I wanted to know if it's
printf() I'm misuing. Here are the snippets:

/* m is of type MYSQL* */
unsigned int code = mysql_errno(m);
const char *description = mysql_error(m);

if(code && description)
{
printf("Failed to create chemistry recipe table.\n"
"Error code: %d\n"
"Description: %s\n", code, description);
}

This snippet doesn't segfault at runtime but the following one does:
printf("Failed to create chemistry recipe table.\n"
"Error code: %d\n"
"Description: %s\n", mysql_errno(m), mysql_error(m));

Both snippets produce the same output though. Is this mis-use of printf() in
the last snippet or a mysql c api problem (if so, I will ask this question
elsewhere)?

Thanks for any help

/ Eric
 
M

Mike Wahler

Eric Lilja said:
Hello, I have two code snippets I want you to look at. My program compiles
without warnings (warning level set to max, gcc 3.4.3) with either snippet
but the latter one causes a segfault at run-time. I know it contains
non-standard constructs (using the MySql C api) but I wanted to know if it's
printf() I'm misuing. Here are the snippets:

/* m is of type MYSQL* */
unsigned int code = mysql_errno(m);
const char *description = mysql_error(m);

if(code && description)
{
printf("Failed to create chemistry recipe table.\n"
"Error code: %d\n"
"Description: %s\n", code, description);
}

This snippet doesn't segfault at runtime but the following one does:
printf("Failed to create chemistry recipe table.\n"
"Error code: %d\n"
"Description: %s\n", mysql_errno(m), mysql_error(m));

Both snippets produce the same output though. Is this mis-use of printf() in
the last snippet or a mysql c api problem (if so, I will ask this question
elsewhere)?

The proper 'printf()' specifier for type 'unsigned int'
is %u. For type 'char *' (or 'const char*') it's %s.
If your supplied arguments' types do not match the
specifiers, the behavior is undefined, in which case
*anything* could happen, from 'segfault' to 'seems to work'
or anything else.

-Mike
 
E

Eric Lilja

"Mike Wahler"wrote:
The proper 'printf()' specifier for type 'unsigned int'
is %u. For type 'char *' (or 'const char*') it's %s.
If your supplied arguments' types do not match the
specifiers, the behavior is undefined, in which case
*anything* could happen, from 'segfault' to 'seems to work'
or anything else.

Thanks for catching that error, Mike. Unfortunately, my problem remains so I
can only assume I've encountered a problem with the mysql c api code. I will
look for an appropriate forum and ask there.

/ Eric
 
M

Mike Wahler

Eric Lilja said:
"Mike Wahler"wrote:

Thanks for catching that error, Mike. Unfortunately, my problem remains so I
can only assume I've encountered a problem with the mysql c api code. I will
look for an appropriate forum and ask there.

You can find out if the 'mysql' stuff is the problem by
removing it from your program and substituting 'dummy'
variables to represent e.g. mysql function return values,
and give those to 'printf()'. Also, note that often a
bug can easily wait to manifest itself until execution
reaches some part of the code other than where the bug
actually is. I.e. 'divide and conquer'. Do your program
in small pieces. Perform unit tests.

-Mike
 
C

Christian Bau

"Eric Lilja said:
Hello, I have two code snippets I want you to look at. My program compiles
without warnings (warning level set to max, gcc 3.4.3) with either snippet
but the latter one causes a segfault at run-time. I know it contains
non-standard constructs (using the MySql C api) but I wanted to know if it's
printf() I'm misuing. Here are the snippets:

/* m is of type MYSQL* */
unsigned int code = mysql_errno(m);
const char *description = mysql_error(m);

if(code && description)
{
printf("Failed to create chemistry recipe table.\n"
"Error code: %d\n"
"Description: %s\n", code, description);
}

This snippet doesn't segfault at runtime but the following one does:
printf("Failed to create chemistry recipe table.\n"
"Error code: %d\n"
"Description: %s\n", mysql_errno(m), mysql_error(m));

Both snippets produce the same output though. Is this mis-use of printf() in
the last snippet or a mysql c api problem (if so, I will ask this question
elsewhere)?

1. In the second code it is not defined in which order mysql_errno and
mysql_error are called. There might be a dependency; maybe mysql_error
returns NULL until after a call to mysql_errno which returns a non-zero
value. Try what happens if you start with
const char *description = mysql_error(m);
unsigned int code = mysql_errno(m);

that is in reverse order.

2. Obviously if mysql_errno returns zero then the output will be
different. Quite possible that mysql_error will then return NULL, which
means the first printf isn't called at all while the second one crashes.

3. Or do you mean you called mysql_errno and mysql_error once before the
printf and then again within the printf? Maybe mysql_errno reports an
error only once (any errors since the previous call to mysql_errno? ),
so the printf will crash.
 
E

Eric Lilja

Christian Bau said:
1. In the second code it is not defined in which order mysql_errno and
mysql_error are called. There might be a dependency; maybe mysql_error
returns NULL until after a call to mysql_errno which returns a non-zero
value. Try what happens if you start with


that is in reverse order.

Very interesting. I tried switching the order and it did indeed alter the
programs behaviour. It didn't cause a crash, but different output.

unsigned int code = mysql_errno(m);
const char *description = mysql_error(m);

if(code && description)
{
printf("Failed to create chemistry recipe table.\n"
"Error code: %u\n"
"Description: %s\n", code, description);
}

yields the output:
Failed to create chemistry recipe table.
Error code: 1050
Description: Table 'chemistry_recipes' already exists

and with the initilizations switched:
const char *description = mysql_error(m);
unsigned int code = mysql_errno(m);

if(code && description)
{
printf("Failed to create chemistry recipe table.\n"
"Error code: %u\n"
"Description: %s\n", code, description);
}
yields this output:
Failed to create chemistry recipe table.
Error code: 10373019
Description: Table 'chemistry_recipes' already exists
(note the different error code)
2. Obviously if mysql_errno returns zero then the output will be
different. Quite possible that mysql_error will then return NULL, which
means the first printf isn't called at all while the second one crashes.

3. Or do you mean you called mysql_errno and mysql_error once before the
printf and then again within the printf? Maybe mysql_errno reports an
error only once (any errors since the previous call to mysql_errno? ),
so the printf will crash.

/ Eric
 
M

Martin Ambuhl

Eric said:
Hello, I have two code snippets I want you to look at. My program compiles
without warnings (warning level set to max, gcc 3.4.3) with either snippet
but the latter one causes a segfault at run-time. I know it contains
non-standard constructs (using the MySql C api) but I wanted to know if it's
printf() I'm misuing. Here are the snippets:

/* m is of type MYSQL* */
unsigned int code = mysql_errno(m);
const char *description = mysql_error(m);

if(code && description)
{
printf("Failed to create chemistry recipe table.\n"
"Error code: %d\n"
"Description: %s\n", code, description);
}

This snippet doesn't segfault at runtime but the following one does:
printf("Failed to create chemistry recipe table.\n"
"Error code: %d\n"
"Description: %s\n", mysql_errno(m), mysql_error(m));

Both snippets produce the same output though.

That I don't understand. If they produce the same output, then the
segfault is probably occurring *after* this line. It is very unlikely
that a line of code will both cause a segfault and be executed with
otherwise expected results.
Is this mis-use of printf() in
the last snippet or a mysql c api problem (if so, I will ask this question
elsewhere)?


The first snippet checks to see if description is NULL; the second does
not check that mysql_error(m) is NULL. There are, then, two probable
scenarios
1) Most likely: The segfault does not occur where you think it does.
2) Less likely: mysql_error(m) is not 0 in the first snippet at the
point that its value is assigned to description, but is 0 in the second
snippet at the point that it is returned to printf.
 
K

Keith Thompson

Eric Lilja said:
Hello, I have two code snippets I want you to look at. My program compiles
without warnings (warning level set to max, gcc 3.4.3) with either snippet
but the latter one causes a segfault at run-time. I know it contains
non-standard constructs (using the MySql C api) but I wanted to know if it's
printf() I'm misuing. Here are the snippets:

/* m is of type MYSQL* */
unsigned int code = mysql_errno(m);
const char *description = mysql_error(m);

if(code && description)
{
printf("Failed to create chemistry recipe table.\n"
"Error code: %d\n"
"Description: %s\n", code, description);
}

This snippet doesn't segfault at runtime but the following one does:
printf("Failed to create chemistry recipe table.\n"
"Error code: %d\n"
"Description: %s\n", mysql_errno(m), mysql_error(m));

Both snippets produce the same output though. Is this mis-use of printf() in
the last snippet or a mysql c api problem (if so, I will ask this question
elsewhere)?

Use "%u", not "%d" to print an unsigned int (but this isn't going to
cause a seg fault).

What are the declared return types of mysql_errno and mysql_error?
Did you include the header that declares them?

And as someone else mentioned, there may be an ordering dependency on
the calls to mysql_errno() and mysql_error() in your second printf().
 
C

CBFalconer

Keith said:
Use "%u", not "%d" to print an unsigned int (but this isn't going
to cause a seg fault).

What are the declared return types of mysql_errno and mysql_error?
Did you include the header that declares them?

And as someone else mentioned, there may be an ordering dependency on
the calls to mysql_errno() and mysql_error() in your second printf().

The first is guarded against 0/NULL values for code/description,
while the second has no such guard to the corresponding printf
arguments. I suspect printf itself is aborting on finding a NULL
to satisfy a %s specification.
 
J

Jonathan Burd

Eric Lilja wrote:
[...]
/* m is of type MYSQL* */
unsigned int code = mysql_errno(m);
const char *description = mysql_error(m);

if(code && description)
{
printf("Failed to create chemistry recipe table.\n"
"Error code: %d\n"
"Description: %s\n", code, description);
}

This snippet doesn't segfault at runtime but the following one does:
printf("Failed to create chemistry recipe table.\n"
"Error code: %d\n"
"Description: %s\n", mysql_errno(m), mysql_error(m));

Both snippets produce the same output though. Is this mis-use of printf() in
the last snippet or a mysql c api problem (if so, I will ask this question
elsewhere)?
[...]

I would suggest against using the latter approach. The calling
conventions being used determine the order in which the arguments are
passed. I would generally avoid calling multiple functions or using
prefix/postfix expressions within argument lists.

Regards,
Jonathan.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,573
Members
45,046
Latest member
Gavizuho

Latest Threads

Top