portability problem with a function returning a struct

Discussion in 'C Programming' started by Army1987, May 16, 2007.

  1. Army1987

    Army1987 Guest

    Under Linux (gcc) this works OK, but under Windows (lcc-win32)
    p.Blue always is zero.
    Within the function itself, result.Blue is correct (either 0, 255,
    or the floor of the expression assigned to it modulo 256, according
    to the sign of n). But when returned to main(), it magically turns
    to zero. (The code below is entirely copied and pasted.)
    What the deuce is happening? Any ideas? sizeof(struct Pixel) is 3,
    if that can matter to anything (but so it is with gcc).

    #define DEBUG
    #include <stdio.h>
    #include <limits.h>
    #include <math.h>

    struct Pixel {
    unsigned char Red;
    unsigned char Green;
    unsigned char Blue;
    } colormap(int n, int max);

    #ifdef DEBUG
    int main(void)
    {
    int n, max;
    while (scanf("%d%d",&n, &max) > 1) {
    struct Pixel p = colormap(n, max);
    printf("%d %d %d\n", (int)p.Red, (int)p.Green,
    (int)p.Blue);
    if (!p.Blue)
    puts("p.Blue is *really* zero.");
    }
    return 0;
    }
    #else
    /*real program*/
    #endif

    struct Pixel colormap(int n, int max)
    {
    struct Pixel result;
    if (n < 1) { /* black if negative, white if zero */
    result.Red = n ? 0 : UCHAR_MAX;
    result.Green = n ? 0 : UCHAR_MAX;
    result.Blue = n ? 0 : UCHAR_MAX;
    } else {
    const double pi = 4 * atan(1);
    double val = UCHAR_MAX*(1 - log(n)/log(max))
    + log(n)/log(max);
    double hue = 2 * pi * log(n) / log(2.0);
    result.Red = val * (1 + cos(hue))/2;
    result.Green = val * (1 + cos(hue - 2*pi/3))/2;
    #ifdef DEBUG
    printf("%g\t", val * (1 + cos(hue - 4*pi/3))/2);
    #endif
    result.Blue = val * (1 + cos(hue - 4*pi/3))/2;
    }
    #ifdef DEBUG
    printf("result.Blue is %d\n", (int)result.Blue);
    #endif
    return result;
    }

    Behaviour with gcc:
    army1987@army1987-laptop:~$ ./a.out
    -1 255
    result.Blue is 0
    0 0 0
    p.Blue is *really* zero.
    0 255
    result.Blue is 255
    255 255 255
    1 255
    63.75 result.Blue is 63
    255 63 63
    42 255
    35.4608 result.Blue is 35
    9 80 35
    23 32767
    144.707 result.Blue is 144
    0 121 144
    ok thanks
    army1987@army1987-laptop:~$

    Behaviour with lcc-win32:
    C:\lcc\projects\lcc>test
    -1 255
    result.Blue is 0
    0 0 0
    p.Blue is *really* zero.
    0 255
    result.Blue is 255
    255 255 0
    p.Blue is *really* zero.
    1 255
    63.75 result.Blue is 63
    255 63 0
    p.Blue is *really* zero.
    42 255
    35.4608 result.Blue is 35
    9 80 0
    p.Blue is *really* zero.
    23 32767
    144.707 result.Blue is 144
    0 121 0
    p.Blue is *really* zero.
    go f*** yourself

    C:\lcc\projects\lcc>
     
    Army1987, May 16, 2007
    #1
    1. Advertising

  2. Army1987 said:

    > Under Linux (gcc) this works OK, but under Windows (lcc-win32)
    > p.Blue always is zero.


    I can't see any obvious issues with the code. I recommend that you try
    to find the simplest possible program that exhibits the same problem,
    and re-post it. For example, if you throw out all the trig, and just
    set the values directly within colormap(), does the problem remain?

    But this does look like a bug in the implementation. No surprise there,
    given the maintainer's attitude to conformance and portability.

    --
    Richard Heathfield
    "Usenet is a strange place" - dmr 29/7/1999
    http://www.cpax.org.uk
    email: rjh at the above domain, - www.
     
    Richard Heathfield, May 18, 2007
    #2
    1. Advertising

  3. In article <f2k988$ns2$>, Army1987 <> wrote:
    >Under Linux (gcc) this works OK, but under Windows (lcc-win32)
    >p.Blue always is zero.


    I'd guess it's a bug in struct return in lcc-win32.

    The question is remarkably similar to

    http://forums.belution.com/en/cpp/000/052/60s.shtml

    -- Richard
    --
    "Consideration shall be given to the need for as many as 32 characters
    in some alphabets" - X3.4, 1963.
     
    Richard Tobin, May 18, 2007
    #3
  4. Army1987

    Army1987 Guest

    "Richard Heathfield" <> ha scritto nel messaggio
    news:...
    > Army1987 said:
    >
    >> Under Linux (gcc) this works OK, but under Windows (lcc-win32)
    >> p.Blue always is zero.

    >
    > I can't see any obvious issues with the code. I recommend that you try
    > to find the simplest possible program that exhibits the same problem,
    > and re-post it. For example, if you throw out all the trig, and just
    > set the values directly within colormap(), does the problem remain?

    Yes, as I showed in the original post:
    struct Pixel colormap(int n, int max)
    {
    struct Pixel result;
    if (n < 1) { /* black if negative, white if zero */
    result.Red = n ? 0 : UCHAR_MAX;
    result.Green = n ? 0 : UCHAR_MAX;
    result.Blue = n ? 0 : UCHAR_MAX;
    } else {
    [snip]
    #ifdef DEBUG
    printf("result.Blue is %d\n", (int)result.Blue);
    #endif
    return result;
    }

    Behaviour with lcc-win32:
    C:\lcc\projects\lcc>test
    [snip]
    0 255
    result.Blue is 255
    255 255 0
    p.Blue is *really* zero.

    > But this does look like a bug in the implementation. No surprise there,
    > given the maintainer's attitude to conformance and portability.

    I guess that, as soon as I manage to have a working Internet
    connection on Linux, I will add the following to every program I'll
    ever write:
    struct Pixel { unsigned char Red, Green, Blue; } ****(void)
    {
    struct Pixel fuck_;
    ****.Red = ****.Green = ****.Blue = 1;
    return ****;
    }
    int main(void) {
    if (!****().Blue) system("format c: /AUTOTEST");
     
    Army1987, May 18, 2007
    #4
  5. Army1987

    Guest

    On 16 May, 17:26, "Army1987" <> wrote:

    > struct Pixel colormap(int n, int max)
    > {
    > struct Pixel result;

    ....
    > return result;
    >
    > }


    What happens to the storage allocated for result at the end of the
    colormap function?
     
    , May 18, 2007
    #5
  6. Army1987

    Army1987 Guest

    "Army1987" <> ha scritto nel messaggio
    news:f2kal1$pmq$...
    > struct Pixel { unsigned char Red, Green, Blue; } ****(void)
    > {
    > struct Pixel fuck_;
    > ****.Red = ****.Green = ****.Blue = 1;

    Yeah, I meant fuck_.Red = etc...
     
    Army1987, May 18, 2007
    #6
  7. Army1987

    Army1987 Guest

    <> ha scritto nel messaggio
    news:...
    > On 16 May, 17:26, "Army1987" <> wrote:
    >
    >> struct Pixel colormap(int n, int max)
    >> {
    >> struct Pixel result;

    > ...
    >> return result;
    >>
    >> }

    >
    > What happens to the storage allocated for result at the end of the
    > colormap function?


    The same which happens with any non-array automatic variable, I
    guess. At least, that is what is supposed to happen.
     
    Army1987, May 18, 2007
    #7
  8. Army1987

    Guest

    On 18 May, 14:45, wrote:
    > On 16 May, 17:26, "Army1987" <> wrote:
    >
    >
    >
    > > struct Pixel colormap(int n, int max)
    > > {
    > > struct Pixel result;

    > ...
    > > return result;

    >
    > > }

    >
    > What happens to the storage allocated for result at the end of the
    > colormap function?


    OOPS - very bad. Forget I said it, though it's probably related in
    some way. As RT suggests it's a bug with lcc-win32's method of
    returning structs, and I'd guess that some compiler "magic" tries to
    make the struct inside colormap() accessible to the caller.
     
    , May 18, 2007
    #8
  9. Army1987 said:

    > "Richard Heathfield" <> ha scritto nel messaggio
    > news:...
    >
    >> But this does look like a bug in the implementation. No surprise
    >> there, given the maintainer's attitude to conformance and
    >> portability.

    > I guess that, as soon as I manage to have a working Internet
    > connection on Linux, I will add the following to every program I'll
    > ever write:
    > struct Pixel { unsigned char Red, Green, Blue; } ****(void)


    Welcome to the bozo bin. See you in 30 days.

    --
    Richard Heathfield
    "Usenet is a strange place" - dmr 29/7/1999
    http://www.cpax.org.uk
    email: rjh at the above domain, - www.
     
    Richard Heathfield, May 18, 2007
    #9
  10. Army1987

    pete Guest

    Army1987 wrote:

    > while (scanf("%d%d",&n, &max) > 1) {


    > 0 0 0


    Are you entering three values
    when your scanf call is only looking for two?

    --
    pete
     
    pete, May 19, 2007
    #10
  11. Army1987

    Barry Guest

    "Army1987" <> wrote in message
    news:f2k988$ns2$...
    > Under Linux (gcc) this works OK, but under Windows (lcc-win32)
    > p.Blue always is zero.
    > Within the function itself, result.Blue is correct (either 0, 255,
    > or the floor of the expression assigned to it modulo 256, according
    > to the sign of n). But when returned to main(), it magically turns
    > to zero. (The code below is entirely copied and pasted.)
    > What the deuce is happening? Any ideas? sizeof(struct Pixel) is 3,
    > if that can matter to anything (but so it is with gcc).
    >
    > #define DEBUG
    > #include <stdio.h>
    > #include <limits.h>
    > #include <math.h>
    >
    > struct Pixel {
    > unsigned char Red;
    > unsigned char Green;
    > unsigned char Blue;
    > } colormap(int n, int max);
    >
    > #ifdef DEBUG
    > int main(void)
    > {
    > int n, max;
    > while (scanf("%d%d",&n, &max) > 1) {
    > struct Pixel p = colormap(n, max);
    > printf("%d %d %d\n", (int)p.Red, (int)p.Green,
    > (int)p.Blue);
    > if (!p.Blue)
    > puts("p.Blue is *really* zero.");
    > }
    > return 0;
    > }
    > #else
    > /*real program*/
    > #endif
    >
    > struct Pixel colormap(int n, int max)
    > {
    > struct Pixel result;
    > if (n < 1) { /* black if negative, white if zero */
    > result.Red = n ? 0 : UCHAR_MAX;
    > result.Green = n ? 0 : UCHAR_MAX;
    > result.Blue = n ? 0 : UCHAR_MAX;
    > } else {
    > const double pi = 4 * atan(1);
    > double val = UCHAR_MAX*(1 - log(n)/log(max))
    > + log(n)/log(max);
    > double hue = 2 * pi * log(n) / log(2.0);
    > result.Red = val * (1 + cos(hue))/2;
    > result.Green = val * (1 + cos(hue - 2*pi/3))/2;
    > #ifdef DEBUG
    > printf("%g\t", val * (1 + cos(hue - 4*pi/3))/2);
    > #endif
    > result.Blue = val * (1 + cos(hue - 4*pi/3))/2;
    > }
    > #ifdef DEBUG
    > printf("result.Blue is %d\n", (int)result.Blue);
    > #endif
    > return result;
    > }
    >


    Just an open question of style. Would most of you write
    this as is or make colormap take the struct as an argument?

    e.g.

    colormap(struct Pixel p, int n, int max);
    or
    colormap(struct Pixel *p, int n, int max);

    In most cases I tend to use the last form.
     
    Barry, May 19, 2007
    #11
  12. Army1987

    Barry Guest

    "Barry" <> wrote in message
    news:...
    >
    > "Army1987" <> wrote in message
    > news:f2k988$ns2$...
    >> Under Linux (gcc) this works OK, but under Windows (lcc-win32)
    >> p.Blue always is zero.
    >> Within the function itself, result.Blue is correct (either 0, 255,
    >> or the floor of the expression assigned to it modulo 256, according
    >> to the sign of n). But when returned to main(), it magically turns
    >> to zero. (The code below is entirely copied and pasted.)
    >> What the deuce is happening? Any ideas? sizeof(struct Pixel) is 3,
    >> if that can matter to anything (but so it is with gcc).
    >>
    >> #define DEBUG
    >> #include <stdio.h>
    >> #include <limits.h>
    >> #include <math.h>
    >>
    >> struct Pixel {
    >> unsigned char Red;
    >> unsigned char Green;
    >> unsigned char Blue;
    >> } colormap(int n, int max);
    >>
    >> #ifdef DEBUG
    >> int main(void)
    >> {
    >> int n, max;
    >> while (scanf("%d%d",&n, &max) > 1) {
    >> struct Pixel p = colormap(n, max);
    >> printf("%d %d %d\n", (int)p.Red, (int)p.Green,
    >> (int)p.Blue);
    >> if (!p.Blue)
    >> puts("p.Blue is *really* zero.");
    >> }
    >> return 0;
    >> }
    >> #else
    >> /*real program*/
    >> #endif
    >>
    >> struct Pixel colormap(int n, int max)
    >> {
    >> struct Pixel result;
    >> if (n < 1) { /* black if negative, white if zero */
    >> result.Red = n ? 0 : UCHAR_MAX;
    >> result.Green = n ? 0 : UCHAR_MAX;
    >> result.Blue = n ? 0 : UCHAR_MAX;
    >> } else {
    >> const double pi = 4 * atan(1);
    >> double val = UCHAR_MAX*(1 - log(n)/log(max))
    >> + log(n)/log(max);
    >> double hue = 2 * pi * log(n) / log(2.0);
    >> result.Red = val * (1 + cos(hue))/2;
    >> result.Green = val * (1 + cos(hue - 2*pi/3))/2;
    >> #ifdef DEBUG
    >> printf("%g\t", val * (1 + cos(hue - 4*pi/3))/2);
    >> #endif
    >> result.Blue = val * (1 + cos(hue - 4*pi/3))/2;
    >> }
    >> #ifdef DEBUG
    >> printf("result.Blue is %d\n", (int)result.Blue);
    >> #endif
    >> return result;
    >> }
    >>

    >
    > Just an open question of style. Would most of you write
    > this as is or make colormap take the struct as an argument?
    >
    > e.g.
    >
    > colormap(struct Pixel p, int n, int max);


    Of course you can scratch this one since it won't work.
    Too early in the morning to be commenting about code.

    > or
    > colormap(struct Pixel *p, int n, int max);
    >
    > In most cases I tend to use the last form.
    >
     
    Barry, May 19, 2007
    #12
  13. In article <>,
    Barry <> wrote:

    >> Just an open question of style. Would most of you write
    >> this as is or make colormap take the struct as an argument?
    >>
    >> e.g.
    >>
    >> colormap(struct Pixel p, int n, int max);


    >Of course you can scratch this one since it won't work.


    True.

    >> colormap(struct Pixel *p, int n, int max);


    The natural thing would be to return the struct, just as it would be
    for an int or any other scalar type. The main reason *not* to return
    a struct is to avoid copying, and for a small struct that is likely to
    be negligible.

    (Incidentally, a common way to implement struct return is for the
    compiler to allocate space in the caller's stack frame, and pass a
    pointer to it. So when the result is assigned to a struct variable it
    might be possible for the compiler to optimise away the copy, and just
    pass in the address of the destination variable. Or it might also be
    able to use the passed-in struct directly in the called function
    instead of allocating a variable there. Or even both, though it would
    have to consider the possibility of the assigned-to struct being
    aliased, and perhaps other things.)

    -- Richard
    --
    "Consideration shall be given to the need for as many as 32 characters
    in some alphabets" - X3.4, 1963.
     
    Richard Tobin, May 19, 2007
    #13
  14. Army1987

    Barry Guest

    "Richard Tobin" <> wrote in message
    news:f2mpnf$26q2$...
    > In article <>,
    > Barry <> wrote:
    >
    >>> Just an open question of style. Would most of you write
    >>> this as is or make colormap take the struct as an argument?
    >>>
    >>> e.g.
    >>>
    >>> colormap(struct Pixel p, int n, int max);

    >
    >>Of course you can scratch this one since it won't work.

    >
    > True.
    >
    >>> colormap(struct Pixel *p, int n, int max);

    >
    > The natural thing would be to return the struct, just as it would be
    > for an int or any other scalar type. The main reason *not* to return
    > a struct is to avoid copying, and for a small struct that is likely to
    > be negligible.
    >
    > (Incidentally, a common way to implement struct return is for the
    > compiler to allocate space in the caller's stack frame, and pass a
    > pointer to it. So when the result is assigned to a struct variable it
    > might be possible for the compiler to optimise away the copy, and just
    > pass in the address of the destination variable. Or it might also be
    > able to use the passed-in struct directly in the called function
    > instead of allocating a variable there. Or even both, though it would
    > have to consider the possibility of the assigned-to struct being
    > aliased, and perhaps other things.)
    >


    It may well turn out I am in the minority opinion of style.
    I think it confuses the issue of functions which malloc() a struct.

    < OT seperate>
    You have to keep in mind there are many C compilers that don't
    support struct assignment at all.
    </OT>

    But my opinion is you already have the object. Why copy it as oppose
    to pass the pointer?

    < MORE OT I find it particularly amusing that lcc is broken. >
     
    Barry, May 19, 2007
    #14
  15. Army1987

    Clark Cox Guest

    On 2007-05-19 07:13:34 -0700, "Barry" <> said:
    >
    > It may well turn out I am in the minority opinion of style.
    > I think it confuses the issue of functions which malloc() a struct.
    >
    > < OT seperate>
    > You have to keep in mind there are many C compilers that don't
    > support struct assignment at all.
    > </OT>


    Then they're not C compilers.


    --
    Clark S. Cox III
     
    Clark Cox, May 19, 2007
    #15
  16. Army1987

    Army1987 Guest

    "pete" <> ha scritto nel messaggio
    news:...
    > Army1987 wrote:
    >
    >> while (scanf("%d%d",&n, &max) > 1) {

    >
    >> 0 0 0

    >
    > Are you entering three values
    > when your scanf call is only looking for two?

    That is the output. Re-read the original post more carefully.
     
    Army1987, May 19, 2007
    #16
  17. "Barry" <> writes:
    [...]
    > < OT seperate>
    > You have to keep in mind there are many C compilers that don't
    > support struct assignment at all.
    > </OT>

    [...]

    Can you provide an example? Struct assignment is required by both C90
    and C99, and I think it was fairly common before the ANSI C89 standard
    was published.

    --
    Keith Thompson (The_Other_Keith) <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."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, May 19, 2007
    #17
  18. Army1987

    Chris Dollin Guest

    Barry wrote:

    > < OT seperate>
    > You have to keep in mind there are many C compilers that don't
    > support struct assignment at all.
    > </OT>


    Name one.

    A /recent/ one; let's say something after 1989.

    (Such a compiler cannot, of course, claim conformance to
    either C standard. I can believe that there could be
    circumstances in which C-without-struct-assignments
    would be good enough for some application.)

    --
    Far-Fetched Hedgehog
    The shortcuts are all full of people using them.
     
    Chris Dollin, May 19, 2007
    #18
  19. Army1987

    Ian Collins Guest

    Richard Tobin wrote:
    > In article <>,
    > Barry <> wrote:
    >
    >>> Just an open question of style. Would most of you write
    >>> this as is or make colormap take the struct as an argument?
    >>>
    >>> e.g.
    >>>
    >>> colormap(struct Pixel p, int n, int max);

    >
    >> Of course you can scratch this one since it won't work.

    >
    > True.
    >
    >>> colormap(struct Pixel *p, int n, int max);

    >
    > The natural thing would be to return the struct, just as it would be
    > for an int or any other scalar type. The main reason *not* to return
    > a struct is to avoid copying, and for a small struct that is likely to
    > be negligible.
    >
    > (Incidentally, a common way to implement struct return is for the
    > compiler to allocate space in the caller's stack frame, and pass a
    > pointer to it. So when the result is assigned to a struct variable it
    > might be possible for the compiler to optimise away the copy, and just
    > pass in the address of the destination variable. Or it might also be
    > able to use the passed-in struct directly in the called function
    > instead of allocating a variable there. Or even both, though it would
    > have to consider the possibility of the assigned-to struct being
    > aliased, and perhaps other things.)
    >

    This technique of return value optimisation (RVO) is a well known and
    often discussed optimisation in the C++ world, so I assume it is common
    in modern C compilers.

    --
    Ian Collins.
     
    Ian Collins, May 19, 2007
    #19
  20. In article <>,
    Barry <> wrote:

    >< OT seperate>
    >You have to keep in mind there are many C compilers that don't
    >support struct assignment at all.
    ></OT>


    Fortunately I don't.

    I suppose there may still be C compilers in use that don't support it
    (as well as some with bugs), but I don't have to worry about them.
    If someone needs to port my code to them, it will be their problem,
    and a good reason for them to find another compiler.

    >But my opinion is you already have the object. Why copy it as oppose
    >to pass the pointer?


    You could say the same for an int, or a double.

    -- Richard
    --
    "Consideration shall be given to the need for as many as 32 characters
    in some alphabets" - X3.4, 1963.
     
    Richard Tobin, May 19, 2007
    #20
    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. Chris Fogelklou
    Replies:
    36
    Views:
    1,393
    Chris Fogelklou
    Apr 20, 2004
  2. Ole
    Replies:
    4
    Views:
    603
    Michael Wojcik
    Oct 26, 2004
  3. Laurent Deniau

    struct initializer efficiency and portability

    Laurent Deniau, Aug 28, 2007, in forum: C Programming
    Replies:
    1
    Views:
    264
    Laurent Deniau
    Aug 28, 2007
  4. Replies:
    12
    Views:
    552
    Richard Herring
    May 20, 2008
  5. DiAvOl
    Replies:
    155
    Views:
    2,525
    Tim Rentsch
    Oct 11, 2008
Loading...

Share This Page