New output model

Discussion in 'C Programming' started by Peter Ammon, Oct 24, 2003.

  1. Peter Ammon

    Peter Ammon Guest

    I invented a new (AFAIK) way of doing the O part of C's I/O that is
    safer than printf() without sacrificing much convenience. It looks a
    bit like C++'s formatted output, without the stupid gotchas (but with
    all of the ugly syntax.)

    It looks like this:

    start()->i(4)->s(" score and ")->f(7)->s(" years ago...")->c('\n');

    This would output

    4 score and 7.000000 years ago...

    Here's some sample code for it.

    #include <stdio.h>

    static const struct funcs *start(void), *print_string(const char*),
    *print_int(int), *print_double(double), *print_char(char);

    static const struct funcs {
    const struct funcs * (*s)(const char*);
    const struct funcs * (*i)(int);
    const struct funcs * (*f)(double);
    const struct funcs * (*c)(char);
    } funcs_val = { print_string, print_int, print_double, print_char };


    static const struct funcs* start(void) {
    return &funcs_val;
    }

    static const struct funcs* print_string(const char* s) {
    fputs(s, stdout);
    return &funcs_val;
    }

    static const struct funcs* print_int(int s) {
    printf("%d", s);
    return &funcs_val;
    }

    static const struct funcs* print_double(double s) {
    printf("%f", s);
    return &funcs_val;
    }

    static const struct funcs* print_char(char s) {
    printf("%c", s);
    return &funcs_val;
    }

    int main(void) {
    start()->i(4)->s(" score and ")->f(7)->s(" years ago...")->c('\n');
    return 0;
    }

    Let me know if you find this useful, can improve on it, point out bugs, etc.

    -Peter
    Peter Ammon, Oct 24, 2003
    #1
    1. Advertising

  2. On Thu, 23 Oct 2003, Peter Ammon wrote:
    >
    > I invented a new (AFAIK) way of doing the O part of C's I/O that is
    > safer than printf() without sacrificing much convenience. It looks a
    > bit like C++'s formatted output, without the stupid gotchas (but with
    > all of the ugly syntax.)


    Hoo yeah. I don't think anyone will ever use this syntax, ever,
    but it *is* a good example of how to do stupid things with operator
    overloading even when the language doesn't support operator
    overloading. :)

    > Let me know if you find this useful, can improve on it, point
    > out bugs, etc.


    It would be prettier if the output functions weren't tied to
    stdout -- that is, if you could write something like

    FILE *fp = ...;
    cxxstr_stream out = cxxstr_open(fp);
    out->i(4)->s(" score and ");

    (The above can't be done in general in C, but can it be done by
    adding some more function calls in an unobtrusive manner?)
    Then obviously you'd add a global object 'cxxstr_cout' that would
    send things to 'stdout', and 'cxxstr_cerr' for 'stderr', and so on.
    I don't want to think about it any more.

    Interesting, though. :)
    -Arthur
    Arthur J. O'Dwyer, Oct 24, 2003
    #2
    1. Advertising

  3. Peter Ammon

    Nick Austin Guest

    On Thu, 23 Oct 2003 17:17:52 -0700, Peter Ammon
    <> wrote:

    >I invented a new (AFAIK) way of doing the O part of C's I/O that is
    >safer than printf() without sacrificing much convenience. It looks a
    >bit like C++'s formatted output, without the stupid gotchas (but with
    >all of the ugly syntax.)
    >
    >It looks like this:
    >
    >start()->i(4)->s(" score and ")->f(7)->s(" years ago...")->c('\n');


    Personally, I'd rather stick with printf.

    However if such a system were forced upon me I'd suggest the
    following:

    >static const struct funcs {
    > const struct funcs * (*s)(const char*);
    > const struct funcs * (*i)(int);


    would be better as long.

    > const struct funcs * (*f)(double);
    > const struct funcs * (*c)(char);


    I would also include the following:
    unsigned long
    pointers (void *)

    Also I would add a second version of each function that allowed
    the format string as an argument. This allows flags, field
    widths, precision and conversion to be specified.

    Finally, for convenience I would include a newline() function.

    The complete function table would therefore be:

    static const struct funcs
    {
    const struct funcs *( *s )( const char * );
    const struct funcs *( *l )( long );
    const struct funcs *( *u )( unsigned long );
    const struct funcs *( *f )( double );
    const struct funcs *( *c )( char );
    const struct funcs *( *p )( void * );
    const struct funcs *( *fs )( const char *, const char * );
    const struct funcs *( *fl )( const char *, long );
    const struct funcs *( *fu )( const char *, unsigned long );
    const struct funcs *( *ff )( const char *, double );
    const struct funcs *( *fp )( const char *, void * );
    const struct funcs *( *newline )( void );
    }

    Nick.
    Nick Austin, Oct 24, 2003
    #3
  4. Peter Ammon

    Daniel Haude Guest

    On Thu, 23 Oct 2003 17:17:52 -0700,
    Peter Ammon <> wrote
    in Msg. <bn9r3d$6sr$>

    > I invented a new (AFAIK) way of doing the O part of C's I/O that is
    > safer than printf() without sacrificing much convenience.


    I LOVE it although I think it's both ugly and useless. A nice example of
    how to make legal ANSI C look like something completely different. I'll
    never use it, and I doubt anybody else (except you, perhaps) will ever use
    it, but it's just so damn clever.

    Thanks!
    --Daniel

    --
    "With me is nothing wrong! And with you?" (from r.a.m.p)
    Daniel Haude, Oct 24, 2003
    #4
  5. Peter Ammon

    CBFalconer Guest

    Peter Ammon wrote:
    >
    > I invented a new (AFAIK) way of doing the O part of C's I/O that
    > is safer than printf() without sacrificing much convenience. It
    > looks a bit like C++'s formatted output, without the stupid
    > gotchas (but with all of the ugly syntax.)
    >
    > It looks like this:
    >
    > start()->i(4)->s(" score and ")->f(7)->s(" years ago...")->c('\n');
    >
    > This would output
    >
    > 4 score and 7.000000 years ago...


    Take a look at how Pascal handles such output. The source code
    would be:

    write(fp, 4, ' score and ', 7.0, ' years ago...');

    or, to impose the final \n:

    writeln(fp, 4, ' score and ', 7.0, ' years ago...');

    with omission of fp causing the output to go to stdout, or the
    equivalent. Each field can also have ": fld" added, to specify
    the size of the field in which to write, and floating point values
    can have ": fld : places" to specify both field and decimal
    places. This is all done within the compiler, and the run time
    has routines for writing each of integers, characters, strings,
    floats, booleans, and line endings.

    The awkward and lengthy C++ syntax is an effort to implement this
    convenience without having the compiler aware of the output
    methods. C is unable to handle it directly without alterations to
    the language, but it could be easily done with an extension.

    In a way you have found an ingenious way to build this around the
    printf family, by replacing the return value from printf itself
    and leaving the type selection to the programmer. You might
    improve it by storing fp in the funcs record, and then adding fp
    to the start routines parameters. This would allow use on any
    text file. Similarly you could create the funcs record with a
    replacement for fopen.

    >
    > Here's some sample code for it.
    >
    > #include <stdio.h>
    >
    > static const struct funcs *start(void), *print_string(const char*),
    > *print_int(int), *print_double(double), *print_char(char);
    >
    > static const struct funcs {
    > const struct funcs * (*s)(const char*);
    > const struct funcs * (*i)(int);
    > const struct funcs * (*f)(double);
    > const struct funcs * (*c)(char);
    > } funcs_val = { print_string, print_int, print_double, print_char };
    >
    > static const struct funcs* start(void) {
    > return &funcs_val;
    > }
    >
    > static const struct funcs* print_string(const char* s) {
    > fputs(s, stdout);
    > return &funcs_val;
    > }
    >
    > static const struct funcs* print_int(int s) {
    > printf("%d", s);
    > return &funcs_val;
    > }
    >
    > static const struct funcs* print_double(double s) {
    > printf("%f", s);
    > return &funcs_val;
    > }
    >
    > static const struct funcs* print_char(char s) {
    > printf("%c", s);
    > return &funcs_val;
    > }
    >
    > int main(void) {
    > start()->i(4)->s(" score and ")->f(7)->s(" years ago...")->c('\n');
    > return 0;
    > }


    --
    Chuck F () ()
    Available for consulting/temporary embedded and systems.
    <http://cbfalconer.home.att.net> USE worldnet address!
    CBFalconer, Oct 25, 2003
    #5
  6. Peter Ammon

    nobody Guest

    "Peter Ammon" <> wrote in message
    news:bn9r3d$6sr$...
    > I invented a new (AFAIK) way of doing the O part of C's I/O that is


    Invention is too strong word, perhaps. But I bet that Patent Office
    would fall for it :)

    > safer than printf() without sacrificing much convenience. It looks a


    Safer in what ways? And it's apparent that our opinions differ
    in what "convenience" means.

    > bit like C++'s formatted output, without the stupid gotchas (but with
    > all of the ugly syntax.)


    I'm failing to see how it's like any's language *formatted* output,
    bit or not-bit. And IMHO syntax is uglier than C++'s (less "natural").

    >
    > It looks like this:
    >
    > start()->i(4)->s(" score and ")->f(7)->s(" years ago...")->c('\n');
    >
    > This would output
    >
    > 4 score and 7.000000 years ago...
    >

    and it would output
    0.000000
    for
    start()->f(0.0000001)->c('\n')
    [snip]
    >
    > Let me know if you find this useful, can improve on it, point out bugs,

    etc.
    >

    It was maybe interesting as an exercise, but impractical due
    - limitations (offers only fraction of functionality of printf(), no
    possibility
    of error detection)
    - at least one bug (see above)
    - performance implications (function calls overhead on top of
    internally used printf() - 11 calls in your example instead of 1)
    - syntax (more typing than for printf())

    For time being, I will stick with printf() family.

    I'm afraid that my answer falls into "etc." category. As saying goes, be
    careful what you wish for ...;-)
    nobody, Oct 25, 2003
    #6
  7. nobody wrote:

    > Safer in what ways?


    If this isn't obvious to you, then I question whether you should be
    using printf() (and similar functions) at all.

    -Kevin
    --
    My email address is valid, but changes periodically.
    To contact me please use the address from a recent posting.
    Kevin Goodsell, Oct 25, 2003
    #7
  8. Peter Ammon

    nobody Guest

    "Kevin Goodsell" <> wrote in message
    news:UMymb.2255$...
    > nobody wrote:
    >
    > > Safer in what ways?

    >
    > If this isn't obvious to you, then I question whether you should be
    > using printf() (and similar functions) at all.
    >

    No, it's not obvious to me, how calling printf() via "wrapper" is safer than
    calling it directly with same argument values (e.g calling print_int(4)
    instead
    of printf("%d", 4)). Also, if one is aware of limitations, implications and
    pittfalls of something, does it imply that (s)he will use it in unsafe way?
    I didn't have yet encounter problems related to usage of printf() family
    functions in programs I wrote so far. I will welcome any substantiation
    of your questioning, or better yet, if you can show me why OP's code
    is safer. I personally don't mind to learn from this NG (or any other
    source,
    for that matter).
    nobody, Oct 25, 2003
    #8
  9. On Sat, 25 Oct 2003, nobody wrote:
    >
    > "Kevin Goodsell" <> wrote...
    > > nobody wrote:
    > > > Safer in what ways?

    > >
    > > If this isn't obvious to you, then I question whether you should be
    > > using printf() (and similar functions) at all.

    >
    > No, it's not obvious to me, how calling printf() via "wrapper" is safer than
    > calling it directly with same argument values (e.g calling print_int(4)
    > instead of printf("%d", 4)).


    extern int printf(const char *, ...);
    extern int print_int(int);

    printf("%d", 4); /* legal and safe */
    print_int(4); /* legal and safe */
    printf("%d", "x"); /* legal and unsafe */
    print_int("x"); /* illegal */

    Variadic functions allow the unwary user to mess up big-time.
    The print_int() style automatically handles implicit conversion
    to the right type, and forces the compiler to warn about incorrect
    usage.

    > Also, if one is aware of limitations, implications and
    > pittfalls of something, does it imply that (s)he will use it in unsafe way?


    Ever done any of the following?

    int *p;
    long l;
    int i;
    printf("%p\n", p);
    printf("%d\n", l);
    printf("%x\n", i);

    Then your code is (technically speaking) incorrect. Variadic
    functions don't perform as many useful conversions as you might
    think. The correct lines would be

    printf("%p\n", (void *) p);
    printf("%ld\n", l);
    printf("%x\n", (unsigned int) i);

    HTH,
    -Arthur
    Arthur J. O'Dwyer, Oct 25, 2003
    #9
  10. nobody wrote:
    >
    > No, it's not obvious to me, how calling printf() via "wrapper" is safer than
    > calling it directly with same argument values (e.g calling print_int(4)
    > instead
    > of printf("%d", 4)). Also, if one is aware of limitations, implications and
    > pittfalls of something, does it imply that (s)he will use it in unsafe way?
    > I didn't have yet encounter problems related to usage of printf() family
    > functions in programs I wrote so far. I will welcome any substantiation
    > of your questioning, or better yet, if you can show me why OP's code
    > is safer. I personally don't mind to learn from this NG (or any other
    > source,
    > for that matter).
    >
    >


    One meaningful metric for "safety" in this case is "the number of
    opportunities for one to make a mistake." printf() gives you many, many
    chances to make a mistake, and the compiler generally cannot help you
    locate such mistakes - they quietly invoke undefined behavior.

    How many ways can you screw up a call to print_xxx() (where xxx is some
    type)? Basically, you can call it with the wrong type. In this case, one
    of two things will happen. Either there is no implicit conversion and
    the compiler will issue a diagnostic, or there is an implicit conversion
    and the result will be well-defined. Nothing bad can happen other than
    the printed result appearing incorrect.

    How many ways can you screw up a printf() call? I doubt I can list them all.

    * Wrong format specifier for the type
    * Wrong size specifier for the type
    * Transposed arguments
    * Too few arguments
    * Too many arguments (technically not an error, but probably a bug)
    * Incorrect argument type after promotion

    Most of these lead to undefined behavior, and the compiler cannot, in
    general, detect the error.

    You've never made one of these mistakes?


    ....are you sure?


    -Kevin
    --
    My email address is valid, but changes periodically.
    To contact me please use the address from a recent posting.
    Kevin Goodsell, Oct 25, 2003
    #10
  11. Peter Ammon

    nobody Guest

    "Arthur J. O'Dwyer" <> wrote in message
    news:p...
    >
    > On Sat, 25 Oct 2003, nobody wrote:
    > >
    > > "Kevin Goodsell" <> wrote...
    > > > nobody wrote:
    > > > > Safer in what ways?
    > > >
    > > > If this isn't obvious to you, then I question whether you should be
    > > > using printf() (and similar functions) at all.

    > >
    > > No, it's not obvious to me, how calling printf() via "wrapper" is safer

    than
    > > calling it directly with same argument values (e.g calling print_int(4)
    > > instead of printf("%d", 4)).

    >
    > extern int printf(const char *, ...);
    > extern int print_int(int);
    >
    > printf("%d", 4); /* legal and safe */
    > print_int(4); /* legal and safe */
    > printf("%d", "x"); /* legal and unsafe */
    > print_int("x"); /* illegal */
    >
    > Variadic functions allow the unwary user to mess up big-time.
    > The print_int() style automatically handles implicit conversion
    > to the right type, and forces the compiler to warn about incorrect
    > usage.
    >
    > > Also, if one is aware of limitations, implications and
    > > pittfalls of something, does it imply that (s)he will use it in unsafe

    way?
    >
    > Ever done any of the following?
    >
    > int *p;
    > long l;
    > int i;
    > printf("%p\n", p);
    > printf("%d\n", l);
    > printf("%x\n", i);
    >

    Hard to say if ever, but I think not in last N years.

    > Then your code is (technically speaking) incorrect. Variadic

    UB

    > functions don't perform as many useful conversions as you might

    I know. They (or rather compiler) can't.

    > think. The correct lines would be
    >
    > printf("%p\n", (void *) p);
    > printf("%ld\n", l);
    > printf("%x\n", (unsigned int) i);
    >

    Thanks for an answer. I've got the point. Though I still stick with
    printf:)-).
    (It was semantic issue /or my lack of understanding English/. This code
    *is* safer, but that doesn't imply everyone not using it will write
    less-safe
    code.)
    nobody, Oct 25, 2003
    #11
  12. Peter Ammon

    nobody Guest

    "Kevin Goodsell" <> wrote in message
    news:qlCmb.2433$...
    > nobody wrote:
    > >
    > > No, it's not obvious to me, how calling printf() via "wrapper" is safer

    than
    > > calling it directly with same argument values (e.g calling print_int(4)
    > > instead
    > > of printf("%d", 4)). Also, if one is aware of limitations, implications

    and
    > > pittfalls of something, does it imply that (s)he will use it in unsafe

    way?
    > > I didn't have yet encounter problems related to usage of printf() family
    > > functions in programs I wrote so far. I will welcome any substantiation
    > > of your questioning, or better yet, if you can show me why OP's code
    > > is safer. I personally don't mind to learn from this NG (or any other
    > > source,
    > > for that matter).
    > >
    > >

    >
    > One meaningful metric for "safety" in this case is "the number of
    > opportunities for one to make a mistake." printf() gives you many, many
    > chances to make a mistake, and the compiler generally cannot help you
    > locate such mistakes - they quietly invoke undefined behavior.
    >
    > How many ways can you screw up a call to print_xxx() (where xxx is some
    > type)? Basically, you can call it with the wrong type. In this case, one
    > of two things will happen. Either there is no implicit conversion and
    > the compiler will issue a diagnostic, or there is an implicit conversion
    > and the result will be well-defined. Nothing bad can happen other than
    > the printed result appearing incorrect.
    >
    > How many ways can you screw up a printf() call? I doubt I can list them

    all.
    >
    > * Wrong format specifier for the type
    > * Wrong size specifier for the type
    > * Transposed arguments
    > * Too few arguments
    > * Too many arguments (technically not an error, but probably a bug)
    > * Incorrect argument type after promotion
    >
    > Most of these lead to undefined behavior, and the compiler cannot, in
    > general, detect the error.
    >
    > You've never made one of these mistakes?
    >
    >
    > ...are you sure?
    >

    Thanks for an answer. Will nor repeat what I've replied to Arthur, but yes,
    I've made at least one of those mistakes in the past, but also I was talking
    about "problems" (hidden bugs discovered by QA or customers) - none of
    these (I'm talking about printf() only). All mistakes were found and
    correected quickly when I tested my code, and hopefully I've better
    knowledge now than some years back.
    nobody, Oct 25, 2003
    #12
  13. Peter Ammon

    James Antill Guest

    On Sat, 25 Oct 2003 21:57:42 +0000, Kevin Goodsell wrote:

    > One meaningful metric for "safety" in this case is "the number of
    > opportunities for one to make a mistake." printf() gives you many, many


    [snip]

    > How many ways can you screw up a printf() call? I doubt I can list them all.
    >
    > * Wrong format specifier for the type
    > * Wrong size specifier for the type
    > * Transposed arguments
    > * Too few arguments
    > * Too many arguments (technically not an error, but probably a bug)
    > * Incorrect argument type after promotion
    >
    > Most of these lead to undefined behavior, and the compiler cannot, in
    > general, detect the error.
    >
    > You've never made one of these mistakes?
    >
    > ...are you sure?


    I've used a static format checker that tells me if I've made any of the
    above, for as long as I can remember. I'm sure I had problems before I did
    that, and I'm sure I haven't since I got told about them at compile time.
    If I had to go back to not having a static format checker, then I guess
    I might look for a way to format data without printf() ... thankfully that
    isn't a problem I have to solve.

    --
    James Antill --
    Need an efficient and powerful string library for C?
    http://www.and.org/vstr/
    James Antill, Oct 26, 2003
    #13
  14. Peter Ammon

    Doug Eleveld Guest

    Very interesting I think. If I was you I might try returning a struct
    instead of a pointer so you could actually add data to the struct as
    you go along. i.e. the start function could have a FILE* or char* of
    where to redirect.

    It would also then use the struct reference '.' which I think looks
    better than '->', although it may be confusing in this context. I
    dont know if it would reduces efficieny or not.

    You do realize that you could use this for formatted input too?

    I think this is very interesting, could you keep me informed as to any
    improvements you make?

    Doug Eleveld
    Doug Eleveld, Oct 27, 2003
    #14
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?Utf-8?B?Tm92aWNl?=
    Replies:
    2
    Views:
    6,621
    Alan Ferrandiz Langley
    Jun 9, 2004
  2. chuck amadi
    Replies:
    1
    Views:
    478
    Larry Bates
    Jun 23, 2004
  3. Replies:
    1
    Views:
    472
    Andreas Wollschlaeger
    Oct 6, 2006
  4. soniyaa 1111
    Replies:
    0
    Views:
    329
    soniyaa 1111
    Feb 24, 2010
  5. Replies:
    2
    Views:
    439
    Thomas 'PointedEars' Lahn
    Mar 11, 2008
Loading...

Share This Page