Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 14 Feb 2006 11:57:18 +0200
From:      Giorgos Keramidas <keramida@ceid.upatras.gr>
To:        "M. Warner Losh" <imp@bsdimp.com>
Cc:        arch@freebsd.org, stefanf@freebsd.org, cperciva@freebsd.org, des@des.no
Subject:   Re: [releng_6 tinderbox] failure on sparc64/sparc64
Message-ID:  <20060214095718.GC967@flame.pc>
In-Reply-To: <20060213.210510.89039143.imp@bsdimp.com>
References:  <43F04494.4030900@freebsd.org> <20060213.094336.118368793.imp@bsdimp.com> <20060214083530.K22079@epsplex.bde.org> <20060213.210510.89039143.imp@bsdimp.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On 2006-02-13 21:05, "M. Warner Losh" <imp@bsdimp.com> wrote:
> In message: <20060214083530.K22079@epsplex.bde.org>
>             Bruce Evans <bde@zeta.org.au> writes:
> : > It won't matter given how I'm going to fix this problem...
> :
> : Why not just access the object as an array of unsigned chars as someone
> : wrote?  Write it out 1 unsigned char at a time for the simple version.
> : This avoids the complications.
>
> Because it has to be fed to the hardware 4 bytes at a time.

That's still possible, using an intermediate unsigned char buffer, or if
that's too much to ask (i.e. because keeping a duplicate copy of the
'foo' structure is a waste of memory), using a 4-byte scratch buffer and
iterating over an (unsigned char *) pointer through `foo'.

I think, that given a `foo' struct defined as:

    struct foo {
        uint32_t a;
        uint16_t b;
        uint16_t c;
        uint8_t  d;
        uint8_t  e;
    };

You are always allowed to use an (unsigned char *) pointer to iterate
through its bytes, as in:

    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    struct foo {
        uint32_t        a;
        uint16_t        b;
        uint16_t        c;
        uint8_t         d;
        uint8_t         e;
    };

    int
    main(void)
    {
        struct foo foo;
        size_t k;

        memset(&foo, 0, sizeof(foo));
        foo.a = 1;
        foo.b = 2;
        foo.c = 3;
        foo.d = 4;
        foo.e = 5;

        for (k = 0; k < sizeof(foo); k++)
            printf("%s%02x", k ? " " : "", *((unsigned char *)&foo + k));
        putchar('\n');
        return EXIT_SUCCESS;
    }

This prints padding bytes correctly here, even with:

    $ CFLAGS='-std=c99 -pedantic' make WARNS=6 foo.c
    [...]
    $ ./foo
    01 00 00 00 02 00 03 00 04 05 00 00
    $

Then, if there's a 4-byte constraint, a single uint32_t can be used as a
'buffer':

    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    struct foo {
        uint32_t        a;
        uint16_t        b;
        uint16_t        c;
        uint8_t         d;
        uint8_t         e;
    };

    int
    main(void)
    {
        struct foo foo;
        size_t k, nbytes;
        uint32_t x;

        memset(&foo, 0, sizeof(foo));
        foo.a = 1;
        foo.b = 2;
        foo.c = 3;
        foo.d = 4;
        foo.e = 5;

        for (k = 0; k < sizeof(foo); k++)
            printf("%s%02x", k ? " " : "", *((unsigned char *)&foo + k));
        putchar('\n');

        for (k = 0; k < sizeof(foo); k += 4) {
            nbytes = sizeof(uint32_t);
            if (sizeof(foo) - k < nbytes) {
                nbytes = sizeof(foo) - k;
                memset(&x, 0, sizeof(x));
            }
            memcpy(&x, ((unsigned char *)&foo + k), nbytes);
            printf("%s%zdb/%08x", k ? " " : "", nbytes, x);
        }
        putchar('\n');
        return EXIT_SUCCESS;
    }

and it seems to work as expected here on a little-endian machine:

    $ ./foo
    01 00 00 00 02 00 03 00 04 05 00 00
    4b/00000001 4b/00030002 4b/00000504

This probably works much better than trying to cast the original into an
array of uint32_t objects too :)




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20060214095718.GC967>