[releng_6 tinderbox] failure on sparc64/sparc64

Giorgos Keramidas keramida at ceid.upatras.gr
Tue Feb 14 01:58:11 PST 2006


On 2006-02-13 21:05, "M. Warner Losh" <imp at bsdimp.com> wrote:
> In message: <20060214083530.K22079 at epsplex.bde.org>
>             Bruce Evans <bde at 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 :)



More information about the freebsd-arch mailing list