printf errrow ! same code differernt result between dev c++ and vc6.0

G

Guest

void show( char *s, ...) is a function seemd like prinf
code
--------------

#include <stdio.h>
#include <stdarg.h>

void show( char *s, ...)
{
va_list stage;
char *ps;
char pchar;
int pint;
double pdouble;
float pfloat;

va_start( stage, s);
{
while (*s)
{
switch (*s)
{
case '%':
{
s++;
switch (*s)
{
case 'f':
case 'F':
pdouble = va_arg(stage, float );
printf("%f", pdouble);
break;

case 'd':
case 'D':
pint = va_arg(stage, int );
printf("%d", pint);
break;


case 's':
case 'S':

ps = va_arg(stage, char* );
printf("%s", ps);
break;

case 'c':
case 'C':
pchar = va_arg(stage, char );
printf("%c", pchar);
break;



}
s++;
break;
}
default:
printf("%c",*s);
s++;
break;

}
}

}
}

int main()
{
int x =55;
char h ='a';
show("%c",h);
show("%c",h);
return 0;
}

---------------------------------------

under vc6.0 it can run well!

but under linux redhat7.x gcc error! win2k +dev c++ 4.98
errow !



case 'c':
case 'C':
pchar = va_arg(stage, char ); // here!!!
printf("%c", pchar);
break;


how to fix
 
W

Walter Roberson

:void show( char *s, ...) is a function seemd like prinf
:code

: va_list stage;

: pdouble = va_arg(stage, float );

: pchar = va_arg(stage, char );

gcc warns about two things:

va.c: In function `show':
va.c:26: warning: `float' is promoted to `double' when passed through `...'
va.c:26: warning: (so you should pass `double' not `float' to `va_arg')
va.c:46: warning: `char' is promoted to `int' when passed through `...'


If you fix those two things then gcc will run the code.

I would hazard a guess that va_arg() is using sizeof()
and you happened to get an unaligned access when you
told it the wrong size.
 
M

Michael Mair

void show( char *s, ...) is a function seemd like prinf
code
--------------

#include <stdio.h>
#include <stdarg.h>

void show( char *s, ...)
{
va_list stage;
char *ps;
char pchar;
int pint;
double pdouble;
float pfloat;

va_start( stage, s);
{
while (*s)
{
switch (*s)
{
case '%':
{
s++;
switch (*s)
{
case 'f':
case 'F':
pdouble = va_arg(stage, float );
printf("%f", pdouble);
break;

case 'd':
case 'D':
pint = va_arg(stage, int );
printf("%d", pint);
break;


case 's':
case 'S':

ps = va_arg(stage, char* );
printf("%s", ps);
break;

case 'c':
case 'C':
pchar = va_arg(stage, char );
printf("%c", pchar);
break;
You need a default here, as you otherwise run into trouble
for the string "%"; after reading '%', you skip over
'\0' without a default label (or a check against *s!=0)...

.... and then step over the '\0' to point to the next character.
Note that this is still legal -- it is evaluating *s which
can bring you into the realm of undefined behaviour (can because
you may be lucky in that the underlying storage s points to is
greater than strlen(s)+1 bytes and one of these bytes is '\0').

For the issues with arguments of variadic functions and va_arg,
Walter's post cleared that up.


Cheers
Michael
 
P

pete

void show( char *s, ...) is a function seemd like prinf
code
--------------

#include <stdio.h>
#include <stdarg.h>

void show( char *s, ...)
{
va_list stage;
char *ps;
char pchar;
int pint;
double pdouble;
float pfloat;

va_start( stage, s);

Where's va_end?

I don't like the extra braces.
It makes it harder to tell which switch is missing a default.
while (*s)
{
switch (*s)
{
case '%':
{
s++;
switch (*s)
{
case 'f':
case 'F':
pdouble = va_arg(stage, float );

Should be double instead of float.
printf("%f", pdouble);
break;

case 'd':
case 'D':
pint = va_arg(stage, int );
printf("%d", pint);
break;

case 's':
case 'S':

ps = va_arg(stage, char* );
printf("%s", ps);
break;

case 'c':
case 'C':
pchar = va_arg(stage, char );

Should be pint instead of pchar and int instead of char.
printf("%c", pchar);
break;

}
s++;
break;
}
default:
printf("%c",*s);
s++;
break;

}
}

}
}

int main()
{
int x =55;
char h ='a';
show("%c",h);
show("%c",h);
return 0;
}

/* BEGIN new.c */

#include <stdio.h>
#include <stdarg.h>

void show( char *s, ...)
{
va_list stage;
char *ps;
int pint;
double pdouble;

va_start( stage, s);
while (*s) {
switch (*s) {
case '%':
switch (*++s) {
case 'f':
case 'F':
pdouble = va_arg(stage, double);
printf("%f", pdouble);
break;
case 'd':
case 'D':
pint = va_arg(stage, int);
printf("%d", pint);
break;
case 's':
case 'S':
ps = va_arg(stage, char*);
printf("%s", ps);
break;
case 'c':
case 'C':
pint = va_arg(stage, int);
printf("%c", pint);
break;
default:
printf("%c", *s);
break;
}
break;
default:
printf("%c", *s);
break;
}
++s;
}
va_end(stage);
}

int main(void)
{
int x = 55;
char h = 'a';

show("%c", h);
show("%c", h);
putchar('\n');
show(
"%%f 9.0 is %f.\n%%d 9 is %d.\n"
"%%s nine is %s.\n%%c '9' is %c.\n",
9.0, 9, "nine", '9'
);
return 0;
}

/* END new.c */
 
M

Martin Ambuhl

(e-mail address removed) wrote:


[code snipped, see replacement below]
under vc6.0 it can run well!

It shouldn't.
but under linux redhat7.x gcc error! win2k +dev c++ 4.98
errow !
case 'c':
case 'C':
pchar = va_arg(stage, char ); // here!!!
printf("%c", pchar);
break;


how to fix

First turn your diagnostics on.

Your error is in not realizing that values are subject to default
promotions when passed to variadic functions. Try the following (my
changes are marked with /* mha ... */ comments):

/* mha: unused variables pfloat (in show) and x (in main) removed */

#include <stdio.h>
#include <stdarg.h>

void show(char *s, ...)
{
va_list stage;
char *ps;
char pchar;
int pint;
double pdouble;

va_start(stage, s);
{
while (*s)
switch (*s) {
case '%':
s++;
switch (*s) {
case 'f':
case 'F':
/* mha: because floats are promoted to doubles when
passed to variadic functions, the type in the next
line has been changed. */
pdouble = va_arg(stage, double /* was 'float' */ );
printf("%f", pdouble);
break;
case 'd':
case 'D':
pint = va_arg(stage, int);
printf("%d", pint);
break;
case 's':
case 'S':

ps = va_arg(stage, char *);
printf("%s", ps);
break;
/* mha: because chars are promoted to ints when
passed to variadic functions, the type in the next
line has been changed. */

case 'c':
case 'C':
pchar = va_arg(stage, int /* was 'char' */ );
printf("%c", pchar);
break;
}
s++;
break;
default:
printf("%c", *s);
s++;
break;

}
}
}

int main()
{
char h = 'a';
show("%c", h);
show("%c", h);
putchar('\n'); /* mha */
return 0;
}
 
G

Guest

put float to double
put char to int
why ?
before ask first question i fix the code like you
but i donot think it is right

i think sizeof (char ) != sizeof(int)
sizeof (float) != sizeof(double)

va_end(stage); // :) i lost it befor but i find the function still work
well, so .....

i want to read the printf() code!

can you post it? thank you
 
P

Peter Nilsson

put float to double
put char to int
why ?

[Please keep some context of what you're replying to.]

The '...' arguments passed to variadic functions like printf are
undergo 'argument promotion'; float arguments are promoted to
double, char is generally promoted to int.
before ask first question i fix the code like you
but i donot think it is right

i think sizeof (char ) != sizeof(int)
sizeof (float) != sizeof(double)

This is irrelevant. You should learn C from a semantics point of
view, not from what or how a given machine implements C.
va_end(stage); // :) i lost it befor but i find the function
still work well, so .....

It may well work on your system, but the standard requires portable
programs to match each va_start with a corresponding va_end before
the function returns.

There have been systems where missing such a va_end will cause
problems.
i want to read the printf() code!

can you post it? thank you

Source code to printf is going to be different for each different
implementation. That said, just about every C development suite
these days comes with source code to the standard libraries.

For most, printf is implemented as a simple wrapper; it's usually
vprintf which does the hard work.
 
W

Walter Roberson

:put float to double
:put char to int
:why ?
:before ask first question i fix the code like you
:but i donot think it is right

;i think sizeof (char ) != sizeof(int)
; sizeof (float) != sizeof(double)

Effectively when you use ... as a placeholder in the function prototype
to signal a use of varargs, you are not declaring the type of each individual
item, so the compiler has to fall back to the old K&R argument calling
conventions, as if you were calling a routine that had no prototype.
The old calling conventions automatically pass floats as doubles, and
pass char as int, and short as int, so that's the behaviour you inherit.
 
P

pete

put float to double
put char to int
why ?

%c is supposed to take an int argument in a printf call.
printf("%f", pdouble);
%f takes a double argument in a printf call.
va_end(stage); // :) i lost it befor
but i find the function still work well, so .....

"Nothing quite encourages as does one's first unpunished crime."
http://fr.ebookslib.com/?a=sa&b=1089
i want to read the printf() code!

can you post it? thank you

min_printf is as far as I've gone
trying to code something like printf.

/* BEGIN min_printf.c */

#include <stdarg.h>
#include <stdio.h>
/*
** Only 5 features from stdio.h,
** are used in min_printf.c:
**
** 1 putc(c, stream)
** 2 stdout
** 3 FILE
** 4 EOF
** 5 int ferror(FILE *stream);
*/
#define put_c(c, stream) (putc((c), (stream)))
#define put_char(c) (put_c((c), stdout))
#define fsput_char(c) \
(put_char(c) == EOF && ferror(stdout) != 0 ? EOF : 1)

int min_printf(const char *s, ...);

static int fsput_s(const char *s);
static int fsput_u(unsigned integer);
static int fsput_u_plus_1(unsigned integer);
static int fsput_d(int integer);

int main(void)
{
min_printf(
"\n%%u 9u is %u.\n%%d 9 is %d.\n"
"%%s \"nine\" is %s.\n%%c '9' is %c.\n",
9u, 9, "nine", '9'
);
return 0;
}

static int fsput_s(const char *s)
{
int count;

for (count = 0; *s != '\0'; ++s) {
if (put_char(*s) == EOF && ferror(stdout) != 0) {
return EOF;
}
++count;
}
return count;
}

static int fsput_d(int integer)
{
int count;

if (0 > integer) {
if (put_char('-') != EOF) {
count = fsput_u_plus_1(-(integer + 1));
if (count != EOF) {
++count;
}
} else {
count = EOF;
}
} else {
count = fsput_u(integer);
}
return count;
}

static int fsput_u(unsigned integer)
{
int count;
unsigned digit, tenth;

tenth = integer / 10;
digit = integer - 10 * tenth + '0';
count = tenth != 0 ? fsput_u(tenth) : 0;
return count != EOF && put_char(digit) != EOF ? count + 1 : EOF;
}

static int fsput_u_plus_1(unsigned integer)
{
int count;
unsigned digit, tenth;

tenth = integer / 10;
digit = integer - 10 * tenth + '0';
if (digit == '9') {
if (tenth != 0) {
count = fsput_u_plus_1(tenth);
} else {
count = put_char('1') == EOF ? EOF : 1;
}
digit = '0';
} else {
count = tenth != 0 ? fsput_u(tenth) : 0;
++digit;
}
return count != EOF && put_char(digit) != EOF ? count + 1 : EOF;
}

int min_printf(const char *s, ...)
{
int count, increment;
va_list ap;

va_start(ap, s);
for (count = 0; *s != '\0'; ++s) {
if (*s == '%') {
switch (*++s) {
case 'c':
increment = fsput_char(va_arg(ap, int));
break;
case 'd':
increment = fsput_d(va_arg(ap, int));
break;
case 's':
increment = fsput_s(va_arg(ap, char *));
break;
case 'u':
increment = fsput_u(va_arg(ap, unsigned));
break;
default:
increment = fsput_char(*s);
break;
}
} else {
increment = fsput_char(*s);
}
if (increment != EOF) {
count += increment;
} else {
count = EOF;
break;
}
}
va_end(ap);
return count;
}

/* END min_printf.c */
 
M

Martin Ambuhl

put float to double
put char to int
why ?

If you will read my post
before ask first question i fix the code like you
but i donot think it is right

i think sizeof (char ) != sizeof(int)
sizeof (float) != sizeof(double)

There is no guarantee that either of these is true. They are also not
relevant.
 

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
474,161
Messages
2,570,891
Members
47,423
Latest member
henerygril

Latest Threads

Top