printf parameter type wrangling

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Michael B Allen

    printf parameter type wrangling

    I'm printing tables of structure members in a terminal and I would like
    to use printf with an arbitrary pointer so that the code is smaller and
    I don't need to switch over ever possible type.

    But the question is - can I pass an arbitrary type (short, double, char *,
    etc) to printf cast as a char * (provided the specified format string is
    appropriate of course)?

    I chose 'char *' because I reasoned it (a pointer) would large enough
    to accommodate any primitive type passed as a function parameter.

    #include <stdlib.h>
    #include <stddef.h>
    #include <stdio.h>

    void
    printf_member(v oid *obj, size_t off, const char *fmt)
    {
    char **p;

    p = (char **)((char *)obj + off);

    printf(fmt, *p);
    }

    struct foo {
    char c;
    float f;
    int i;
    char *s;
    };

    int
    main(void)
    {
    struct foo f = { 'c', 2.34f, 100, "hello, world" };

    printf_member(& f, offsetof(struct foo, c), "[c]\n");
    printf_member(& f, offsetof(struct foo, f), "[%f]\n");
    printf_member(& f, offsetof(struct foo, i), "[%d]\n");
    printf_member(& f, offsetof(struct foo, s), "[%s]\n");

    return 0;
    }

    Unfortunately this technique does not appear to work as the float member
    was not printed properly. Why?

    $ gcc -Wall -W -ansi -pedantic -o pa pa.c
    $ ./pa
    [c]
    [0.000000]
    [100]
    [hello, world]

    Thanks,
    Mike

  • Emmanuel Delahaye

    #2
    Re: printf parameter type wrangling

    Michael B Allen wrote on 21/08/05 :[color=blue]
    > I'm printing tables of structure members in a terminal and I would like
    > to use printf with an arbitrary pointer so that the code is smaller and
    > $ gcc -Wall -W -ansi -pedantic -o pa pa.c
    > $ ./pa
    > [c]
    > [0.000000]
    > [100]
    > [hello, world][/color]

    Sounds too complicated to me... This is how I do :

    #include <stdlib.h>
    #include <stddef.h>
    #include <stdio.h>

    #define FMT_S "%-5s"

    #define PRT_C(struct_, field_) \
    printf (FMT_S" = '%c'\n" \
    , #struct_ "." #field_ \
    , struct_.field_)

    #define PRT_F(struct_, field_) \
    printf (FMT_S" = %f\n" \
    , #struct_ "." #field_ \
    , struct_.field_)

    #define PRT_I(struct_, field_) \
    printf (FMT_S" = %d\n" \
    , #struct_ "." #field_ \
    , struct_.field_)

    #define PRT_S(struct_, field_) \
    printf (FMT_S" = '%s'\n" \
    , #struct_ "." #field_ \
    , struct_.field_)

    struct foo
    {
    char c;
    float f;
    int i;
    char *s;
    };

    int main (void)
    {
    struct foo f =
    {'c', 2.34f, 100, "hello, world"};

    PRT_C (f, c);
    PRT_F (f, f);
    PRT_I (f, i);
    PRT_S (f, s);

    return 0;
    }

    Output :

    f.c = 'c'
    f.f = 2.340000
    f.i = 100
    f.s = 'hello, world'

    --
    Emmanuel
    The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
    The C-library: http://www.dinkumware.com/refxc.html

    ..sig under repair


    Comment

    • Richard Tobin

      #3
      Re: printf parameter type wrangling

      In article <pan.2005.08.21 .20.18.50.82171 4@ioplex.com>,
      Michael B Allen <mba2000@ioplex .com> wrote:
      [color=blue]
      >But the question is - can I pass an arbitrary type (short, double, char *,
      >etc) to printf cast as a char * (provided the specified format string is
      >appropriate of course)?[/color]

      No.
      [color=blue]
      >I chose 'char *' because I reasoned it (a pointer) would large enough
      >to accommodate any primitive type passed as a function parameter.[/color]

      There are two problems here.

      First, you are accessing a char * at a place in the struct that does
      not necessarily have one. If the object at that location is smaller
      than a char * (a char or short perhaps), then you will get some extra
      rubbish from another part of the struct or perhaps some (arbitrary)
      padding. If it is larger (a double perhaps), you won't get all of it.

      Even if the thing there is the same size as a char *, you might (on
      some architectures) get some bit pattern that causes an error when
      treated as a char * (e.g. when loaded into a address register).
      This doesn't happen on most architectures, but might in theory.

      Second, you are passing a char * to printf when it expects something
      else, and the something else may not be passed in the same way as a
      char *. That is almost certainly the cause of the behaviour you're
      seeing. If a real float were passed to printf, it would be promoted to
      a double, and printf will access a double-sized object at the location
      where you have passed only a char *-sized one.

      Your char * member works (because it *is* a char *). Your int member
      happens to work because int is the same size as char * (and it
      wouldn't have been promoted to anything, being an int). And your char
      member works because you forgot the % sign and the char happens to be
      'c':
      [color=blue]
      > struct foo f = { 'c', 2.34f, 100, "hello, world" };
      >
      > printf_member(& f, offsetof(struct foo, c), "[c]\n");[/color]
      ^ should be %c

      The only way to get this to work is to pass printf an argument of the
      right type. Since you have to pass in something indicating the right
      format for the type, you could instead pass some indication of the
      type (e.g. using an enum) and then have a switch in printf_member that
      covers all the possible cases.

      -- Richard

      Comment

      • Michael B Allen

        #4
        Re: printf parameter type wrangling

        On Sun, 21 Aug 2005 21:09:37 +0000, Richard Tobin wrote:
        [color=blue]
        > The only way to get this to work is to pass printf an argument of the
        > right type. Since you have to pass in something indicating the right
        > format for the type, you could instead pass some indication of the
        > type (e.g. using an enum) and then have a switch in printf_member that
        > covers all the possible cases.[/color]

        Drat! Ok. I'll have to use a big switch. I have the type information in
        a parallel 'cols' array (stored with the format specifier). I was just
        exercising my minimalist instincts.

        Thanks for the quick answers as always,
        Mike

        Comment

        • Pramod Subramanyan

          #5
          Re: printf parameter type wrangling

          [color=blue]
          > Drat! Ok. I'll have to use a big switch.[/color]

          Not really, look at this

          #include <stdio.h>

          struct foo {
          int i; char c; char* s; double f; long l;
          } f = { 848, '~', "Stuff to be said", 4.5, 7474l };

          print_1(char* fmt, int* data) {
          return printf(fmt, *data);
          }

          print_2(char* fmt, double* data) {
          return printf(fmt, *data);
          }
          int main() {
          print_1("%d", &f.i); putchar('\n');
          print_1("%c", &f.c); putchar('\n');
          print_1("%s", &f.s); putchar('\n');
          print_2("%f", &f.f); putchar('\n');
          print_2("%ld", &f.l); putchar('\n');

          return 0;
          }

          The point is that ints,chars,char * and the like are passed in one word
          (on 32 bit machines) and longs, double etc. are passed as two words. So
          you can use one function for the 32 bit data or lesser sized data and
          another for the 64 bit sized data.

          The problem here is float. Float is actually 32 bit, put is passed as a
          double (64 bit). So you can't use either function for floats. Maybe you
          could add a third function and then the size of your switch would be
          reduced quite a bit.

          Comment

          • Richard Tobin

            #6
            Re: printf parameter type wrangling

            In article <1124717703.322 771.98020@g43g2 000cwa.googlegr oups.com>,
            Pramod Subramanyan <pramodsubraman yan@yahoo.co.in > wrote:
            [color=blue]
            > print_1("%s", &f.s); putchar('\n');
            > print_2("%f", &f.f); putchar('\n');[/color]

            That doesn't help much, because you have to know which function to call.

            In any case, it's not usually wise to rely on knowing the size of
            the datatypes. Especially if you're wrong about it:
            [color=blue]
            >The point is that ints,chars,char * and the like are passed in one word
            >(on 32 bit machines) and longs, double etc. are passed as two words.[/color]

            Long is 32 bits on most 32-bit processors.

            In any case, the big switch is not very big. There aren't that many
            built-in datatypes (assuming you don't need to handle pointers other
            than strings).

            -- Richard

            Comment

            • Pramod Subramanyan

              #7
              Re: printf parameter type wrangling

              > That doesn't help much, because you have to know which function to call.

              1) I've heard of an operator called sizeof. Our learned friend here
              perhaps needs to revisit the basics.
              2) Moreover, even though our learned friend is not the person asking
              question, he has however arbitrarily and pre-emptorily appointed him
              sole and final judge of the usefulness of the solution. On what basis,
              may I ask?
              [color=blue]
              > In any case, it's not usually wise to rely on knowing the size of
              > the datatypes. Especially if you're wrong about it:
              > Long is 32 bits on most 32-bit processors.[/color]

              Its 64 bits on Intel based platforms, which form the biggest chunk of
              the market by a LONG (pun unintended) margin, hence the "most". Anyway,
              won't a sizeof solve that problem as well?

              P.S: Richard, you need to do some REAL programming. Portability issues
              aren't as simple as not using the sizes of datatypes. In fact, they're
              one of the simplest problems to solve.

              Comment

              • Keith Thompson

                #8
                Re: printf parameter type wrangling

                "Pramod Subramanyan" <pramodsubraman yan@yahoo.co.in > writes:[color=blue]
                > Richard Tobin <richard@cogsci .ed.ac.uk> writes:[color=green]
                >> In any case, it's not usually wise to rely on knowing the size of
                >> the datatypes. Especially if you're wrong about it:
                >> Long is 32 bits on most 32-bit processors.[/color]
                >
                > Its 64 bits on Intel based platforms, which form the biggest chunk of
                > the market by a LONG (pun unintended) margin, hence the "most". Anyway,
                > won't a sizeof solve that problem as well?[/color]

                Type long is 32 bits in every implementation I've see for 32-bit Intel
                platforms. I've seen 64-bit longs on 64-bit Intel platforms. (Type
                long long is, of course, required to be at least 64 bits.)

                And, Pramod, please don't snip attributions. I had to manually add
                the "Richard Tobin .. writes" above.

                --
                Keith Thompson (The_Other_Keit h) kst-u@mib.org <http://www.ghoti.net/~kst>
                San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
                We must do something. This is something. Therefore, we must do this.

                Comment

                • Pramod Subramanyan

                  #9
                  Re: printf parameter type wrangling


                  Keith Thompson wrote:[color=blue]
                  > "Pramod Subramanyan" <pramodsubraman yan@yahoo.co.in > writes:[color=green]
                  > > Richard Tobin <richard@cogsci .ed.ac.uk> writes:[color=darkred]
                  > >> In any case, it's not usually wise to rely on knowing the size of
                  > >> the datatypes. Especially if you're wrong about it:
                  > >> Long is 32 bits on most 32-bit processors.[/color]
                  > >
                  > > Its 64 bits on Intel based platforms, which form the biggest chunk of
                  > > the market by a LONG (pun unintended) margin, hence the "most". Anyway,
                  > > won't a sizeof solve that problem as well?[/color]
                  >
                  > Type long is 32 bits in every implementation I've see for 32-bit Intel
                  > platforms. I've seen 64-bit longs on 64-bit Intel platforms. (Type
                  > long long is, of course, required to be at least 64 bits.)[/color]

                  VC++, BC++, LCC and a whole bunch of other platforms on Win32 have 64
                  bit longs. Given that Intel has something like 85% of the PC-Processor
                  market, and Windows is used on 80% of those, I stick to my stand. [I
                  may be wrong about the exact numbers, but they're certainly in the same
                  region.] And may I add that you haven't seen too many implementations ?

                  Moreover, the whole concept 32/64bit processors is ambiguous. What are
                  you talking about? Data bus widths, register sizes, memory addressing
                  capability, or instruction pointer (or program counter if you like)
                  widths? Simply calling a processor 32bit or a platform 64bit does not
                  give any real information.

                  Comment

                  • Keith Thompson

                    #10
                    Re: printf parameter type wrangling

                    "Pramod Subramanyan" <pramodsubraman yan@yahoo.co.in > writes:[color=blue]
                    > Keith Thompson wrote:[color=green]
                    >> "Pramod Subramanyan" <pramodsubraman yan@yahoo.co.in > writes:[color=darkred]
                    >> > Richard Tobin <richard@cogsci .ed.ac.uk> writes:
                    >> >> In any case, it's not usually wise to rely on knowing the size of
                    >> >> the datatypes. Especially if you're wrong about it:
                    >> >> Long is 32 bits on most 32-bit processors.
                    >> >
                    >> > Its 64 bits on Intel based platforms, which form the biggest chunk of
                    >> > the market by a LONG (pun unintended) margin, hence the "most". Anyway,
                    >> > won't a sizeof solve that problem as well?[/color]
                    >>
                    >> Type long is 32 bits in every implementation I've see for 32-bit Intel
                    >> platforms. I've seen 64-bit longs on 64-bit Intel platforms. (Type
                    >> long long is, of course, required to be at least 64 bits.)[/color]
                    >
                    > VC++, BC++, LCC and a whole bunch of other platforms on Win32 have 64
                    > bit longs. Given that Intel has something like 85% of the PC-Processor
                    > market, and Windows is used on 80% of those, I stick to my stand. [I
                    > may be wrong about the exact numbers, but they're certainly in the same
                    > region.] And may I add that you haven't seen too many implementations ?[/color]

                    I've seen many implementations ; few of them run under Windows.
                    I believe you're mistaken.

                    Under lcc-win32, long is 32 bits. The following program:

                    #include <stdio.h>
                    #include <limits.h>

                    int main(void)
                    {
                    printf("short is %d bits\n", sizeof(short) * CHAR_BIT);
                    printf("int is %d bits\n", sizeof(int) * CHAR_BIT);
                    printf("long is %d bits\n", sizeof(long) * CHAR_BIT);
                    return 0;
                    }

                    prints

                    short is 16 bits
                    int is 32 bits
                    long is 32 bits

                    I get the same output using gcc under Cygwin under Windows XP.

                    The system in question has an Intel Pentium M processor (IA-32).

                    Can you demonstrate, using the output of the above program, a C
                    implementation on a 32-bit Intel processor (define the term "32-bit"
                    as you like) that has 64-bit long? Please specify the platform, the
                    compiler, and the actual output of the program.
                    [color=blue]
                    > Moreover, the whole concept 32/64bit processors is ambiguous. What are
                    > you talking about? Data bus widths, register sizes, memory addressing
                    > capability, or instruction pointer (or program counter if you like)
                    > widths? Simply calling a processor 32bit or a platform 64bit does not
                    > give any real information.[/color]

                    Agreed.

                    These details are only peripherally topical; the point is that
                    assuming particular sizes for the predefined types is unwise.

                    --
                    Keith Thompson (The_Other_Keit h) kst-u@mib.org <http://www.ghoti.net/~kst>
                    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
                    We must do something. This is something. Therefore, we must do this.

                    Comment

                    • Zoran Cutura

                      #11
                      Re: printf parameter type wrangling

                      Pramod Subramanyan <pramodsubraman yan@yahoo.co.in > wrote:[color=blue]
                      >
                      > Keith Thompson wrote:[color=green]
                      >> "Pramod Subramanyan" <pramodsubraman yan@yahoo.co.in > writes:[color=darkred]
                      >> > Richard Tobin <richard@cogsci .ed.ac.uk> writes:
                      >> >> In any case, it's not usually wise to rely on knowing the size of
                      >> >> the datatypes. Especially if you're wrong about it:
                      >> >> Long is 32 bits on most 32-bit processors.
                      >> >
                      >> > Its 64 bits on Intel based platforms, which form the biggest chunk of
                      >> > the market by a LONG (pun unintended) margin, hence the "most". Anyway,
                      >> > won't a sizeof solve that problem as well?[/color]
                      >>
                      >> Type long is 32 bits in every implementation I've see for 32-bit Intel
                      >> platforms. I've seen 64-bit longs on 64-bit Intel platforms. (Type
                      >> long long is, of course, required to be at least 64 bits.)[/color]
                      >
                      > VC++, BC++, LCC and a whole bunch of other platforms on Win32 have 64
                      > bit longs. Given that Intel has something like 85% of the PC-Processor
                      > market, and Windows is used on 80% of those, I stick to my stand. [I
                      > may be wrong about the exact numbers, but they're certainly in the same
                      > region.] And may I add that you haven't seen too many implementations ?[/color]

                      When I compile the following little prog with VSC++ 6.0

                      #include <limits.h>
                      #include <stdio.h>

                      int main(void)
                      {

                      printf("bits in char == %d\n", CHAR_BIT);
                      printf("size of long == %d\n", (int)sizeof(lon g));
                      return 0;
                      }

                      I get the follwing output:

                      bits in char == 8
                      size of long == 4

                      Which tells me, that long has 4 * 8 Bits which according to Adam Riese would be
                      32. But I may be wrong.
                      [color=blue]
                      >
                      > Moreover, the whole concept 32/64bit processors is ambiguous. What are
                      > you talking about? Data bus widths, register sizes, memory addressing
                      > capability, or instruction pointer (or program counter if you like)
                      > widths? Simply calling a processor 32bit or a platform 64bit does not
                      > give any real information.[/color]

                      You where talking about the size of longs, wheren't you? I suppose that
                      even on 64 Bit-Architectures longs may be 32 bits wide.

                      --
                      Z (zoran.cutura@w eb.de)
                      "LISP is worth learning for the profound enlightenment experience
                      you will have when you finally get it; that experience will make you
                      a better programmer for the rest of your days." -- Eric S. Raymond

                      Comment

                      • Flash Gordon

                        #12
                        Re: printf parameter type wrangling

                        Pramod Subramanyan wrote:[color=blue]
                        > Keith Thompson wrote:
                        >[color=green]
                        >>"Pramod Subramanyan" <pramodsubraman yan@yahoo.co.in > writes:
                        >>[color=darkred]
                        >>>Richard Tobin <richard@cogsci .ed.ac.uk> writes:
                        >>>
                        >>>>In any case, it's not usually wise to rely on knowing the size of
                        >>>>the datatypes. Especially if you're wrong about it:
                        >>>>Long is 32 bits on most 32-bit processors.
                        >>>
                        >>>Its 64 bits on Intel based platforms, which form the biggest chunk of
                        >>>the market by a LONG (pun unintended) margin, hence the "most". Anyway,
                        >>>won't a sizeof solve that problem as well?[/color]
                        >>
                        >>Type long is 32 bits in every implementation I've see for 32-bit Intel
                        >>platforms. I've seen 64-bit longs on 64-bit Intel platforms. (Type
                        >>long long is, of course, required to be at least 64 bits.)[/color]
                        >
                        > VC++, BC++, LCC and a whole bunch of other platforms on Win32 have 64
                        > bit longs.[/color]

                        I can't comment on BC++ or LCC, but you are wrong about VC++. I know
                        because I have it installed. To quote from the Fundamental Types page of
                        the help:

                        | Sizes of Fundamental Types
                        |
                        | Type Size
                        | bool 1 byte
                        | char, unsigned char, signed char 1 byte
                        | short, unsigned short 2 bytes
                        | int, unsigned int 4 bytes __intn 1, 2, 4, or 8
                        | bytes depending on the value of
                        | n. __intn is Microsoft-specific.
                        | long, unsigned long 4 bytes
                        | float 4 bytes
                        | double 8 bytes
                        | long double(1) 8 bytes
                        | long long Equivalent to __int64.
                        |
                        | (1) The representation of long double and double is identical.
                        | However, long double and double are separate types.

                        So unless you are claiming the CHAR_BIT is something other than 8, long
                        is definitely 32 bits.
                        [color=blue]
                        > Given that Intel has something like 85% of the PC-Processor
                        > market, and Windows is used on 80% of those, I stick to my stand. [I
                        > may be wrong about the exact numbers, but they're certainly in the same
                        > region.] And may I add that you haven't seen too many implementations ?[/color]

                        I would not be surprised if Keith has seen rather more implementations
                        that you.
                        [color=blue]
                        > Moreover, the whole concept 32/64bit processors is ambiguous. What are
                        > you talking about? Data bus widths, register sizes, memory addressing
                        > capability, or instruction pointer (or program counter if you like)
                        > widths? Simply calling a processor 32bit or a platform 64bit does not
                        > give any real information.[/color]

                        Since it was Intel processors that were referred to, the most probable
                        definition is whether Intel claim them to be 32 or 64 bit processors.
                        --
                        Flash Gordon
                        Living in interesting times.
                        Although my email address says spam, it is real and I read it.

                        Comment

                        • Richard Tobin

                          #13
                          Re: printf parameter type wrangling

                          In article <1124771730.574 183.292790@g43g 2000cwa.googleg roups.com>,
                          Pramod Subramanyan <pramodsubraman yan@yahoo.co.in > wrote:
                          [color=blue][color=green]
                          >> That doesn't help much, because you have to know which function to call.[/color]
                          >
                          >1) I've heard of an operator called sizeof.[/color]

                          The original poster seemed to want a single function call that worked
                          for all built-in types. Your proposal didn't do that. If you can fix
                          it up using sizeof, that might be useful.

                          The rest of your post consists of insults and a factual error which
                          others have corrected, so I will not address it.

                          -- Richard

                          Comment

                          • Pramod Subramanyan

                            #14
                            Re: printf parameter type wrangling

                            Sorry, I got this wrong.

                            Richard, I apologize for the patronizing tone.

                            Comment

                            • Keith Thompson

                              #15
                              Re: printf parameter type wrangling

                              "Pramod Subramanyan" <pramodsubraman yan@yahoo.co.in > writes:[color=blue]
                              > Sorry, I got this wrong.
                              >
                              > Richard, I apologize for the patronizing tone.[/color]

                              Since Pramod didn't provide context, I'll mention that what he got
                              wrong was his claim that type long is commonly 64 bits on 32-bit Intel
                              platforms.

                              --
                              Keith Thompson (The_Other_Keit h) kst-u@mib.org <http://www.ghoti.net/~kst>
                              San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
                              We must do something. This is something. Therefore, we must do this.

                              Comment

                              Working...