printf() and scanf() questions

I

Ioannis Vranos

The questions are about C95.



printf() questions:

1. printf() provides "%f" format specifier for double. Usually
implemented as a variadic function how can it discern if the argument is
float or double? Shouldn't we cast to double when passing a float value?
If an implicit conversion takes place, at what stage does it take place?
Consider as an example:

printf("%f\n", 123.45F);


2. The same question also applies when printing a signed char value with
"%d" format specifier.



scanf() questions:

1. scanf() provides the "%f" specifier for float. How can it discern
when we pass a double?


Example:

double x;

scanf("%f", &x);

If an implicit conversion to double takes place, at what stage does it
take place? Also if such conversion takes place how it works when using
a float variable?

Example:

float b;

scanf("%f", &b);
 
W

Walter Roberson

The questions are about C95.
printf() questions:
1. printf() provides "%f" format specifier for double. Usually
implemented as a variadic function how can it discern if the argument is
float or double? Shouldn't we cast to double when passing a float value?
If an implicit conversion takes place, at what stage does it take place?
Consider as an example:
printf("%f\n", 123.45F);

My first reaction upon reading this was "Homework!". But I know you
from other groups so I know you would not do that to us.

The answer is that for functions that do not have a prototype, and
the non-prototyped positions of varadic function calls, the
values passed *always* undergo "the usual argument promotions".
Those promote any passed (single precision) float to double,
-before- the receiving function sees it. The compiler knows to do
this promotion because it knows what the type of the actual argument
is, and it knows that it is handing it to a varadic or non-prototyped
function.

scanf() questions:

1. scanf() provides the "%f" specifier for float. How can it discern
when we pass a double?

%f indicates floating point in general, not the type 'float'.
If you are supplying a pointer to a float, you use "%hf".
If you are supplying a pointer to a double, you use "%f".
If you are supplying a pointer to a long double, you use "%Lf".
 
M

Martin Ambuhl

Ioannis said:
1. printf() provides "%f" format specifier for double. Usually
implemented as a variadic function

printf is always a variadic function.
how can it discern if the argument is
float or double?

The float argument, following the normal rules for arguments, is
promoted to a double. Both float and double arguments are presented to
printf as doubles.
Shouldn't we cast to double when passing a float value?
No.


2. The same question also applies when printing a signed char value with
"%d" format specifier.

The answer is analogous, and you should look in the index of your
elementary C text for something like "usual arithmetic conversions". If
an expression appears as an argument in a function call not governed by
a prototype, or when the expression appears as an argument in the
...." part of a prototype, the default function conversions are the same
as (C89 or C90) the usual arithmetic conversions or (C99) the unsual
unitary conversions except float is always promoted to double.
scanf() questions:

1. scanf() provides the "%f" specifier for float. How can it discern
when we pass a double?

You don'r ever pass scanf a double (unless you want it to fail). You
pass an address which the "%f" tells printf to interpret as a
pointer-to-float. If you want it to treat it as a pointer-to-double use
"%lf". This should be adequately covered in any elementary introduction
to C. The rest of your questions depend on your mistaken idea that you
are passing floats or doubles as arguments.
 
R

Richard Tobin

1. printf() provides "%f" format specifier for double. Usually
implemented as a variadic function
[/QUOTE]
printf is always a variadic function.

Presumably by "implemented as a variadic function" the OP meant
implemented in the same way as user-defined variadic functions,
i.e. with stdarg.

If you look back in this group, you will find several posts claiming
that the *printf() functions don't have to work that way, and that you
can't therefore pass a char * for %p.

-- Richard
 
A

Andrey Tarasevich

Ioannis said:
printf() questions:

1. printf() provides "%f" format specifier for double. Usually
implemented as a variadic function how can it discern if the argument is
float or double?

There's no need to discern that. 'float' arguments that correspond to
'...' parameters are implicitly promoted and passed as 'double' parameters.
Shouldn't we cast to double when passing a float value?

No, the promotion will do it implicitly.
If an implicit conversion takes place, at what stage does it take place?

At the stage when the parameter list for the future function call is formed.
2. The same question also applies when printing a signed char value with
"%d" format specifier.

The same thing happens, except the 'int' type is used as the target type
for the implicit promotion.
scanf() questions:

1. scanf() provides the "%f" specifier for float. How can it discern
when we pass a double?

We don't ever pass a 'double' to 'scanf'. We pass either 'float*' or
'double*'. (I hope you understand the difference between a 'double' and
a 'double*'). 'float*' and 'double*' are two different unrelated pointer
types. When we pass a 'float*' (for '%f'), it is passed and processed
internally as as a 'float*'. When we pass a 'double*' (for '%lf'), it is
passed and processed internally as 'double*'. That's it.
If an implicit conversion to double takes place, at what stage does it
take place?

There's no possibility for any implicit conversion here. Especially for
a "conversion to double".
 
A

Andrey Tarasevich

Walter said:
%f indicates floating point in general, not the type 'float'.
If you are supplying a pointer to a float, you use "%hf".
If you are supplying a pointer to a double, you use "%f".
If you are supplying a pointer to a long double, you use "%Lf".

I haven't checked the very-very latest changes in the standard, but I
don't believe they can be that drastic. In the original edition of C99

- 'h' cannot be used in '%f'
- '%f' takes a 'float*' argument, '%lf' takes a 'double*' argument
 
M

Micah Cowan

My first reaction upon reading this was "Homework!". But I know you
from other groups so I know you would not do that to us.

The answer is that for functions that do not have a prototype, and
the non-prototyped positions of varadic function calls, the
values passed *always* undergo "the usual argument promotions".
Those promote any passed (single precision) float to double,
-before- the receiving function sees it. The compiler knows to do
this promotion because it knows what the type of the actual argument
is, and it knows that it is handing it to a varadic or non-prototyped
function.

Note that all of this applies to variadic functions in C++ (where
Ioannis frequents) as well; and so in particular std::printf() can be
depended upon to work the same way there (at least in this
respect). Likewise for promotion of, say, char and unsigned char to
int (when sizeof(int) != 1; else unsigned char would be promoted to
unsigned int [in both C and C++]).
%f indicates floating point in general, not the type 'float'.
If you are supplying a pointer to a float, you use "%hf".
If you are supplying a pointer to a double, you use "%f".
If you are supplying a pointer to a long double, you use "%Lf".

Er, no. %f takes a float, %lf takes a double, and %Lf takes a long
double. The 'h' length modifier is used to specify (signed or
unsigned) short int only.
 
I

Ioannis Vranos

Reminder: About C95.


Walter said:
My first reaction upon reading this was "Homework!". But I know you
from other groups so I know you would not do that to us.


Not a homework. I am actually revisiting my C95 knowledge, while I have
been using the more convenient C++ I/O facilities with the overloaded
member functions for all types for some time.

The answer is that for functions that do not have a prototype, and
the non-prototyped positions of varadic function calls, the
values passed *always* undergo "the usual argument promotions".


I am not sure what you mean by this. #include <stdio.h> is assumed in my
printf() code and I am not using the implicit C function declaration stuff.

From this sentence of yours: "non-prototyped positions of varadic
function calls," I assume you mean the "..." stuff. Here is why I
wonder. Inside the definition of a variadic function we define the "type
step" of va_arg, based on an assumed input type, so if we expect double
we do:

[va_list curr_item;

double curr_val;
... ]


curr_val= va_arg(curr_item, double);


so if we pass a float and %f is about double, we will use the above
expression, with the wrong "step type".


Those promote any passed (single precision) float to double,
-before- the receiving function sees it. The compiler knows to do
this promotion because it knows what the type of the actual argument
is, and it knows that it is handing it to a varadic or non-prototyped
function.



%f indicates floating point in general, not the type 'float'.


What does this "in general" mean? Works for both float and double? My
(Greek) K&R2 mentions (translated) that

"e, f, g floating point number; float *. ...."



If you are supplying a pointer to a float, you use "%hf".
If you are supplying a pointer to a double, you use "%f".
If you are supplying a pointer to a long double, you use "%Lf".


Also my C99 (although off topic since I am talking about C95) mentions
about fscanf():

"h Specifies that a following d, i, o, u, x, X, or n conversion
specifier applies to an argument with type pointer to short int or
unsigned short int.241)".


I do not think "%hf" for scanf() was in C90/C95 and has been removed
from C99, also with K&R 2 mentioning "%f" is for float *.
 
I

Ioannis Vranos

Reminder: About C95.


Walter said:
My first reaction upon reading this was "Homework!". But I know you
from other groups so I know you would not do that to us.


Not a homework. I am actually revisiting my C95 knowledge, while I have
been using the more convenient C++ I/O facilities with the overloaded
member functions for all types for some time.

The answer is that for functions that do not have a prototype, and
the non-prototyped positions of varadic function calls, the
values passed *always* undergo "the usual argument promotions".


I am not sure what you mean by this. #include <stdio.h> is assumed in my
printf() code and I am not using the implicit C function declaration stuff.

From this sentence of yours: "non-prototyped positions of variadic
function calls," I assume you mean the "..." stuff. Here is why I
wonder. Inside the definition of a variadic function we define the "type
step" of va_arg, based on an assumed input type, so if we expect double
we do:

[va_list curr_item;

double curr_val;
... ]


curr_val= va_arg(curr_item, double);


so if we pass a float and %f is about double, we will use the above
expression, with the wrong "step type".


Those promote any passed (single precision) float to double,
-before- the receiving function sees it. The compiler knows to do
this promotion because it knows what the type of the actual argument
is, and it knows that it is handing it to a varadic or non-prototyped
function.



%f indicates floating point in general, not the type 'float'.


What does this "in general" mean? Works for both float and double? My
(Greek) K&R2 mentions (translated) that

"e, f, g floating point number; float *. ...."



If you are supplying a pointer to a float, you use "%hf".
If you are supplying a pointer to a double, you use "%f".
If you are supplying a pointer to a long double, you use "%Lf".


Also my C99 (although off topic since I am talking about C95) mentions
about fscanf():

"h Specifies that a following d, i, o, u, x, X, or n conversion
specifier applies to an argument with type pointer to short int or
unsigned short int.241)".


I do not think "%hf" for scanf() was in C90/C95 and has been removed
from C99, also with K&R 2 mentioning "%f" is for float *.
 
I

Ioannis Vranos

Micah said:
Er, no. %f takes a float, %lf takes a double, and %Lf takes a long
double. The 'h' length modifier is used to specify (signed or
unsigned) short int only.


You got my scanf() question answered: I did not remember that there was
a separate specifier for double, the "%lf", I thought "%f" was for both.
 
M

Micah Cowan

Ioannis Vranos said:
You got my scanf() question answered: I did not remember that there
was a separate specifier for double, the "%lf", I thought "%f" was for
both.

To improve consistency, C99 has added "%lf" to printf() as equivalent
to "%f"; however, using it in pre-C99 code gives undefined behavior,
so it's best avoided on code meant for pre-C99 implementations.
 
M

Micah Cowan

Ioannis Vranos said:
I am not sure what you mean by this. #include <stdio.h> is assumed in
my printf() code and I am not using the implicit C function
declaration stuff.

Right. He's just saying that what he's saying applies to
implicitly-defined functions in addition to the rest.
From this sentence of yours: "non-prototyped positions of variadic
function calls," I assume you mean the "..." stuff.
Yup.

Here is why I
wonder. Inside the definition of a variadic function we define the
"type step" of va_arg, based on an assumed input type, so if we expect
double we do:

[va_list curr_item;

double curr_val;
... ]


curr_val= va_arg(curr_item, double);


so if we pass a float and %f is about double, we will use the above
expression, with the wrong "step type".

Nope. He explains why here:

float is always promoted to double when passing it as an argument
through "...". Note that this implies that

curr_val= va_arg(curr_item, float);

Is never correct, no matter what you pass in.
 
M

Martin Ambuhl

Walter said:
%f indicates floating point in general, not the type 'float'.

Wrong. "%f", "%a", "%e", and "%g" are for floats.
If you are supplying a pointer to a float, you use "%hf".

Wrong. "%f", "%a", "%e", and "%g" are for floats;
the 'h' prefix has meaning only in "%hd", "%hi", "%hu", "%ho", "%hx",
and "%hn". "%hf" is incoherent nonsense.
If you are supplying a pointer to a double, you use "%f".

Wrong. "%lf", "%la", "%le", and "%lg" are for doubles. See above.
If you are supplying a pointer to a long double, you use "%Lf".

At least you got one right. Have you ever considered knowing what
you're talking about before giving answers?
 
M

Mark McIntyre

> Wrong. "%f", "%a", "%e", and "%g" are for floats.

Are you sure?

7.19.6.2(12)
"a,e,f,g Matches an optionally signed floating-point number,
whose format is
the same as expected for the subject sequence of the strtod function.
The corresponding argument shall be a pointer to floating."

Note that strtod converts its argument to a double.

Myself, I suspect this part of the Standard needs reworded.
Correct.

"%f", "%a", "%e", and "%g" are for floats;

For the wrong reason... :)
Wrong.
Incorrect.

"%lf", "%la", "%le", and "%lg" are for doubles.

though this is correct :)
Have you ever considered knowing what you're talking about before giving answers?

You might want to review that remark.
 
I

Ioannis Vranos

Mark said:
Incorrect.

AFAIK "%f" format sepcifier for fscanf()/scanf()is for float *. K&R2
says so. It also says that "%lf" is for double and "%Lf" for long double.
 
I

Ioannis Vranos

Ioannis said:
AFAIK "%f" format sepcifier for fscanf()/scanf()is for float *. K&R2
says so. It also says that "%lf" is for double and "%Lf" for long double.


I remind you, I am talking about C95 here.
 
M

Martin Ambuhl

Mark said:
Are you sure?
Yes.

7.19.6.2(12)
"a,e,f,g Matches an optionally signed floating-point number,
whose format is
the same as expected for the subject sequence of the strtod function.
The corresponding argument shall be a pointer to floating."

Note that strtod converts its argument to a double.

Myself, I suspect this part of the Standard needs reworded.

Yourself, you need to read. "a,e,f,g" in the above refers to the
conversion operation and are not full specifiers. "%f" is a specifier,
in which the optional size specification is empty. It is not the same
thing at all.

I have mercifully snipped the remainder of your nonsense. Except:

You might want to review that remark.

I have. I know what I'm talking about. You haven't a clue.
 
M

Martin Ambuhl

Ioannis said:
AFAIK "%f" format sepcifier for fscanf()/scanf()is for float *. K&R2
says so. It also says that "%lf" is for double and "%Lf" for long double.

Pay no attention to Mark McIntyre. He doesn't have a clue.
 
R

Richard

Mark McIntyre said:
Are you sure?

7.19.6.2(12)
"a,e,f,g Matches an optionally signed floating-point number,
whose format is the same as expected for the subject sequence of the
strtod function. The corresponding argument shall be a pointer to
floating."

You are talking nonsense again.

These are conversion operations and not conversion specifications. You
will notice the absence of the %. Perhaps you should take your own
advice and RTFM?


A word of advice : taking the CLC "standard" of being an obnoxious know
all can leave you looking very stupid indeed.
 
C

CBFalconer

Ioannis said:
The questions are about C95.

printf() questions:

1. printf() provides "%f" format specifier for double. Usually
implemented as a variadic function how can it discern if the argument is
float or double? Shouldn't we cast to double when passing a float value?
If an implicit conversion takes place, at what stage does it take place?

No. printf doesn't specify variable types for the variadic
params. So the standard promotions for arguments take place. That
means all chars and shorts will be passed as ints, all floats as
doubles, etc.
 

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,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top