dirty stuff: f(int,int) cast to f(struct{int,int})

Discussion in 'C Programming' started by Schnoffos, Jun 27, 2003.

  1. Schnoffos

    Schnoffos Guest

    Given two functions:

    f (T1 a, T2 b, ... Tn z)

    and

    g (struct {T1 a; T2 b; ... Tn z} s)

    i wonder how portable it is to call them (proper casts provided) using
    the respecitve other signature, for example:

    f( {a, b, .. z} );

    g (a, b, ..z);

    The question implies that I don't believe this is correct C at all,
    but I wonder if there are compilers that crash on this.

    Reasons for crashes could be different padding of structures and
    argument lists, which I believe will seldom occure (if padding is used
    for structures it will probably also be used for actual argument
    lists). Another reason may be different ordering of arguments such
    that for f(a,b,c) &a < &b is not necessarily true.

    It seems probable to me, that though this is theoretically unportable
    and simply invalid C code, it will in pratice work on most if not all
    current compilers and platforms.

    Is this correct? Can you provide me with examples where this does or
    does not work?

    I used the following code to test it:

    --- snip ---

    struct sii { char x; int y; };

    void f_ii (char x, int y) { printf ("%c, %d\n", x, y); }
    void f_sii (struct sii s){ printf ("%c, %d\n", s.x, s.y); }

    void (*fp_ii)(char x, int y);
    void (*fp_sii)(struct sii);

    main ()
    {
    fp_ii = f_ii;
    fp_ii ('1', 2);
    fp_ii = (void (*)(char, int))f_sii;
    fp_ii ('1', 2);
    }

    --- snip ---

    Greetings & Thanks

    PS: If you reply by mail, please replace utech.de with t-online.de
     
    Schnoffos, Jun 27, 2003
    #1
    1. Advertising

  2. Schnoffos

    Chris Torek Guest

    In article <>
    Schnoffos <> writes:
    >Given two functions:
    >
    >f (T1 a, T2 b, ... Tn z)
    >
    >and
    >
    >g (struct {T1 a; T2 b; ... Tn z} s)
    >
    >i wonder how portable it is to call them (proper casts provided) using
    >the respecitve other signature, for example:
    >
    >f( {a, b, .. z} );
    >
    >g (a, b, ..z);
    >
    >The question implies that I don't believe this is correct C at all,
    >but I wonder if there are compilers that crash on this.


    It is not correct, and there are compilers that produce code
    that fails at runtime (whether it "crashes" or does something
    else is a bit hard to predict, but in any case, it does not
    work).

    >Reasons for crashes could be different padding of structures and
    >argument lists, which I believe will seldom occure (if padding is used
    >for structures it will probably also be used for actual argument
    >lists). Another reason may be different ordering of arguments such
    >that for f(a,b,c) &a < &b is not necessarily true.


    There are other possibilities, one of which is definitely used today.

    >It seems probable to me, that though this is theoretically unportable
    >and simply invalid C code, it will in pratice work on most if not all
    >current compilers and platforms.


    Specifically, if some of the types Tn are "simple" integral
    or pointer types, or even floating-point types, compilers for
    Sun SPARC hardware will pass the ordinary parameters in
    ordinary registers:

    void f(int a, int b, int c, int d) {
    /*
    * any code here that uses "a" through "d"
    * will refer, internally, to the machine's
    * "%o0" through "%o3" registers, or (if there
    * is a SAVE instruction) %i0 through %i3.
    */
    ...
    }

    In function g(), however, the (single) parameter has a structure
    type. The caller will pass the address of either the original or
    a copy (I forget which) and the callee will then assume that the
    (single) incoming parameter has type "pointer to struct unnamed".
    If the caller does not copy, the callee may have to do so, but
    in any case:

    struct unnamed { int a, b, c, d; };

    void g(struct unnamed arg) {
    /*
    * any code here that uses arg.a through arg.d
    * will cause the compiler to treat register %o0
    * (or %i0 after a SAVE) as a pointer to a
    * structure, and refer to [%o0 + 0] through
    * [%o0 + 12] respectively.
    */
    ...
    }

    If you actually call g() with four integer parameters in %o0 through
    %o3, g() will treat the first one as if it were a pointer. Depending
    on the value, the code might then crash, or simply produce wrong
    answers. If you actually pass a structure to f(), the apparent
    "value" of "a" will be the low 32 bits of the address of the original
    or copy (again, I forget which) structure, while the values of b
    through d will be whatever happens to be lying around in %o1 through
    %o3 at the time.
    --
    In-Real-Life: Chris Torek, Wind River Systems (BSD engineering)
    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    email: forget about it http://67.40.109.61/torek/index.html (for the moment)
    Reading email is like searching for food in the garbage, thanks to spammers.
     
    Chris Torek, Jun 27, 2003
    #2
    1. Advertising

  3. On 26 Jun 2003 19:29:55 -0700,
    Schnoffos <> wrote:
    > Given two functions:
    >
    > f (T1 a, T2 b, ... Tn z)
    >
    > and
    >
    > g (struct {T1 a; T2 b; ... Tn z} s)
    >
    > i wonder how portable it is to call them (proper casts provided) using
    > the respecitve other signature, for example:
    >
    > f( {a, b, .. z} );
    >
    > g (a, b, ..z);
    >
    > The question implies that I don't believe this is correct C at all,
    > but I wonder if there are compilers that crash on this.


    It isn't correct C at all.

    > Reasons for crashes could be different padding of structures and
    > argument lists, which I believe will seldom occure (if padding is used
    > for structures it will probably also be used for actual argument
    > lists). Another reason may be different ordering of arguments such
    > that for f(a,b,c) &a < &b is not necessarily true.


    As far as C is concerned, there is no such thing as padding for an
    argument list. How arguments are communicated to a function's body is
    left to the implementation.

    > It seems probable to me, that though this is theoretically unportable
    > and simply invalid C code, it will in pratice work on most if not all
    > current compilers and platforms.


    I don't agree. Maybe your idea of "most current compilers and
    platforms" differs from mine (see below).

    > Is this correct? Can you provide me with examples where this does or
    > does not work?


    I think I can show a few examples of this not "working", in various
    manners.

    Code to test (basically yours, including stdio, and fixed up main()):

    #include <stdio.h>

    struct sii { char x; int y; };

    void f_ii (char x, int y) { printf ("%c, %d\n", x, y); }
    void f_sii (struct sii s){ printf ("%c, %d\n", s.x, s.y); }

    void (*fp_ii)(char x, int y);
    void (*fp_sii)(struct sii);

    int main(void)
    {
    fp_ii = f_ii;
    fp_ii ('1', 2);
    fp_ii = (void (*)(char, int))f_sii;
    fp_ii ('1', 2);
    return 0;
    }

    \begin{offtopic}

    On linux, gcc 3.2:

    $ gcc -fpack-struct -Wall -W -ansi -pedantic foo.c
    $ ./a.out
    1, 2
    1, 33554432


    On linux, Intel compiler:

    $ /opt/intel/compiler70/ia32/bin/icc -Zp1 -ansi foo.c
    $ ./a.out
    1, 2
    1, 33554432

    $ /opt/intel/compiler70/ia32/bin/icc -Zp2 -ansi foo.c
    $ ./a.out
    1, 2
    1, 131072


    On Solaris, gcc 2.95.2:

    $ gcc -Wall -W -ansi -pedantic foo.c
    $ ./a.out
    1, 2
    zsh: segmentation fault ./a.out

    $ gcc -O2 -Wall -W -ansi -pedantic foo.c
    $ ./a.out
    1, 2
    zsh: bus error ./a.out


    Solaris with Sun's compiler:

    $ /opt/SUNWspro/bin/cc foo.c
    $ ./a.out
    1, 2
    zsh: segmentation fault ./a.out

    \end{offtopic}

    Martien
    --
    |
    Martien Verbruggen | Begin at the beginning and go on till you
    Trading Post Australia | come to the end; then stop.
    |
     
    Martien Verbruggen, Jun 27, 2003
    #3
    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. Replies:
    4
    Views:
    537
  2. Chris Fogelklou
    Replies:
    36
    Views:
    1,405
    Chris Fogelklou
    Apr 20, 2004
  3. Kenneth Bull

    Struct/Union pointer stuff

    Kenneth Bull, Apr 14, 2008, in forum: C Programming
    Replies:
    1
    Views:
    423
    Peter Nilsson
    Apr 14, 2008
  4. Kenneth Bull

    struct/union pointer/address stuff.

    Kenneth Bull, Apr 14, 2008, in forum: C Programming
    Replies:
    1
    Views:
    564
    Chris Torek
    Apr 15, 2008
  5. Sébastien de Mapias
    Replies:
    2
    Views:
    302
Loading...

Share This Page