Re: ES format
From: Dave Thompson (david.thompson1_at_worldnet.att.net)
Date: 05/27/04
- Next message: E. Robert Tisdale: "Re: C++ Fortran mixed programming"
- Previous message: Dave Thompson: "Re: Fortran decimal anyone?"
- In reply to: TimC: "Re: ES format"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: Thu, 27 May 2004 01:20:10 GMT
On Wed, 19 May 2004 06:24:25 GMT, TimC
<tconnors@no.astro.spam.swin.accepted.edu.here.au> wrote:
> Dave Thompson (aka Bruce) was almost, but not quite, entirely unlike tea:
> > On Tue, 11 May 2004 11:55:31 GMT, TimC
> > <tconnors@no.astro.spam.swin.accepted.edu.here.au> wrote:
> >
> > <snipped Fortran format/datatype matching>
> >
> >> Of course, I recently found out gcc interprets printf arguments way
> >> beyond I thought would be possible, concidering there is no
> >> run-time-type information available in the C language.
> >>
> > _gcc_ (or rather cc1, the compiler) checks matching of *printf and
> > *scanf arguments only if you use a literal format string. If you use a
> > runtime format, even a runtime format that is trivially constant, not.
> >
> > The actual implementations of these routines in _glibc_ can't and
> > don't check.
>
> That's what I thought. I was surprised though that it bothered to do
> funny things with constant format strings. I think the moral of the
Well, probably about 99% of all *printf and *scanf calls have a
literal format string -- after macro expansion and especially when you
include usages of things like GNU gettext that may vary the actual
value at runtime for i18n/l10n but provide a typical or default value
at compile time -- so while this checking doesn't cover everything it
is a significant convenience. I'd bet roughly the same fraction of
Fortran formatted (and not list or namelist) I/Os use constant strings
or FORMAT statements, hence are checkable at compile time -- except
where matching is affected by the (runtime) range of an implied-do or
variable-size array or section, which fraction I can't guess.
> story is don't go and define your own function and call it "printf()",
> and expect it to work :)
>
You aren't allowed by Standard C to define any _external_ linkage
(global) function (or variable) with the same name as _any_ standard
library function. In practice on many implementations you can,
although in some cases, especially things like malloc(), if you don't
implement exactly the same semantics as the library routine, including
any special ones added by the implementation beyond those required in
the Standard, it will royally screw things up. I haven't personally
encountered a case of printf being depended on in this way, but I
wouldn't bet on it not occurring anywhere.
You can define a 'static' (which in C at file scope means internal
linkage or private) function with any name not reserved _in that
translation unit (= preprocessed source file)_. Stdlib function names
are so reserved (as identifiers and macros) if and only if you
#include (perhaps indirectly) the related header, in this case
<stdio.h>. (The specific header; C standard headers may not
gratuitously #include each other, or as-if, but _C++_ ones may.)
In particular you certainly can define a 'static' function printf(),
or an 'extern' function with some other name like myprintf(), that has
the same functionality as standard printf(). Or similar. Or (very?)
different, but that would be perverse. Although in practice it is
usually impossible to implement *printf functionality without using
some of the "lower level" things also from <stdio.h> like putc() and
FILE, so to be safe you would have to filter them through a wrapper.
It is feasible, though a pain, to do sprintf or snprintf, or their v
and/or w variants -- that is, the ones that write to a string buffer,
like Fortran internal WRITE -- and for [v]snprintf in particular,
which wasn't standard before C99, people actually did/do.
In gcc _only_, you can also declare your function with __attribute__
((format ...)) and get the same checking on calls as for standard
*printf or similarly *scanf or strftime. But only the exact same
checking; if you want to do something similar in concept but different
in detail like handle _Fortran_ format strings, or perl formats or
pack/unpack specs, or COBOL pictures, you get no assistance.
> (I think this suprise discovery came when I found a distinct lack of
> the word "float" in man 3 printf. The %e flag is for a double. What
> happens then when you supply to printf a variable format string, and
> pass a real? Is this disallowed by the standard?)
As already answered, you can't actually pass a float (which is what C
calls a s.p. real) to a vararg, which *printf data arguments are; it
gets promoted to double. Similarly integer types 'below' int (char,
short, and in C99 or C++ _Bool/bool) get promoted to int (or possibly
its unsigned variant); so using a h or (in C99) hh modifier in *printf
is actually redundant. But not for *scanf, where the format modifier
or default must correctly agree with the 'size', which C99 now calls
'(promotion) rank', of the target variable/object. This asymmetry is
sufficiently often confusing to be 12.9 and 15.2 in the C FAQ.
As also already noted, these same 'default argument promotions' also
apply in calls to unprototyped aka K&R1 functions; but all of the
standard functions are (or at least should be) prototyped.
And in <m165as4b2b.fsf@macfortran.local> glen herrmannsfeldt
<gah@ugcs.caltech.edu> writes:
>
> > Richard Maine wrote:
> > (snip)
> >
> > > I'll avoid showing off my lack of C proficiency here, but as a side
> > > note I will observe that quite a few Fortran compilers have been
> > > known to to compile-time checks of things in format statements or
> > > constant format strings, even though there are other cases that
> > > must be deferred until run-time. Sounds comparable to me.
> >
> > I suppose it is. It seems a little less obvious, as printf()
> > is a function, not a statement. It might be that with the
> > proper declarations you can define your own function named
> > printf, but otherwise it is part of the language and the compiler
> > can treat it in a special way.
>
See above. But you must in effect declare it either way; if it isn't
(defined as) your own static routine, you must #include <stdio.h> to
declare it: in C89 because the standard one is a vararg function, and
it is not legal (and in some implementations doesn't work) to call a
vararg function without a proper declaration; and in C99 (and C++)
because you no longer can call undeclared functions at all.
(Technically you may write out the declaration for a standard
function, instead of #include'ing the standard header, if you can do
so without using header-defined types, and printf does fall in this
category; but it's too confusing and fragile to do this in general.)
> Argh...ok...now I'll have to lay my poor C understanding out for
> all to see. :-(
>
> But I think that the C compiler is also allowed to treat functions
> like printf() specially provided that the appropriate header is
> included (presumably <stdio.h>, if the man page on my Mac is to be
> belived, which it probably is). So I really do think they are
> pretty comparable.
The C standard specifies nearly all of the things in its standard
library so that they can be, and conventionally are, implemented as
actual functions, in the C meaning which includes subroutines. And
such out-of-line bodies must exist, as you may take (and use) the
address of any stdlib function; cf. Fortran intrinsics some of which
are usable as EXTERNALs but some not. (A handful of things that cannot
be done with normal function-call semantics, like setjmp, are
specified explicitly as macros and not functions.)
But the standard explicitly permits the implementation to _also_
#define macros which 'shadow' the functions, and/or to implement
stdlib functions by means other than C code; as well as the 'as-if'
rule that blanketly permits anything that produces the same external
effects as the canonical effects specified by the standard. If you
define your own printf() or whatever, within the limitations above,
calls to it must execute your function in the normal fashion. But if
you are referencing the standard one, yes the compiler is permitted to
recognize it and do special stuff.
For example, it would be permitted to recognize printf ("%s\n", s) and
do puts (s) instead. Or fprintf (f, "%d", x) to fputs (_itoa(x), f).
I don't know any compiler that does, and on average it would provide
little or no benefit, but it would be legal. It's not even clear if
the stdlib functions which take varargs -- *printf and *scanf -- must
use the same vararg mechanism as user-defined vararg functions; this
was recently debated on comp.std.c without resolution. I personally
think a difference is permitted, but cannot imagine any modern
platform where it would make sense. The only even rhetorical example I
could come up with is a machine where 'ordinary' calls can cross
privilege levels, like Multics.
This license is usually used only with the simplest stdlib functions,
like memset(), memcpy(), memcmp(), isalpha(), tolower(), and such; on
some (many?) machines these can reasonably be #define'd as macros
which generate and/or recognized by the compiler and implemented by
simple inline code. Theoretically it would be allowed to inline printf
in the same way, but in practice it would be a horrible pessimization.
- David.Thompson1 at worldnet.att.net
- Next message: E. Robert Tisdale: "Re: C++ Fortran mixed programming"
- Previous message: Dave Thompson: "Re: Fortran decimal anyone?"
- In reply to: TimC: "Re: ES format"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Relevant Pages
|