Search code examples
cmemoryendiannessmemset

memset char * with Integer


I have to memset 4 bytes in a char * with an integer.

For exemple I have an integer int i = 3276854 (0x00320036) and a char header[54] = {0}. I have to write i at header + 2, as if I print memory from header[2] to header[6], I get :

0032 0036

I tried this:

memset(&header[2], i, 1);

But it seems to put only the last byte into header, I get :

0036 0000

I also tried:

memset(&header[2], i, 4);

But it fill each byte with the last byte of i, I get :

3636 3636

I also tried to use binary masks like that :

ft_memset(&header[2], (int)(54 + size) & 0xff000000, 1);
ft_memset(&header[3], (int)(54 + size) & 0x00ff0000, 1);
ft_memset(&header[4], (int)(54 + size) & 0x0000ff00, 1);
ft_memset(&header[5], (int)(54 + size) & 0x000000ff, 1);

I get :

3600 0000.

So I don't know how I can get my 0032 0036, or at least 3600 3200 (maybe there is a thing with little and big endian into that, because I run it under MacOS, which is big endian).


Solution

  • memset fills memory with a constant byte value. The second parameter (of type int) is converted to an unsigned char value.

    You could use memcpy like this:

    memcpy(&header[2], &i, sizeof(i));
    

    However, it depends what exactly you are trying to achieve. If the header needs the integer to be in a particular format, you may need to convert the value in some way. For example, if the value needs to be big-endian (which is also known as "network byte order" in several Internet protocols), you can convert it with the htonl function:

    uint32_t bi = htonl(i);
    memcpy(&header[2], &bi, sizeof(bi));
    

    (The htonl function is defined by #include <arpa/inet.h>.)

    Also check the newer byte order conversion functions htobe16, htole16, be16toh, le16toh, htobe32, htole32, be32toh, le32toh, htobe64, htole64, be64toh, and le64toh declared by:

    #define _BSD_SOURCE
    #include <endian.h>
    

    These convert between host byte order and little-endian byte order, or between host byte order and big-endian byte order, and work on uint16_t, uint32_t or uint64_t values, depending on the function name.

    If there are no equivalents to those byte-order conversion functions provided on your system the following non-optimized, but portable (on implementations that support uint16_t, uint32_t and uint64_t) functions may be used:

    myendian.h

    #ifndef MYENDIAN_H__INCLUDED_
    #define MYENDIAN_H__INCLUDED_
    
    #include <stdint.h>
    
    uint16_t my_htobe16(uint16_t h16);
    uint16_t my_htole16(uint16_t h16);
    uint16_t my_be16toh(uint16_t be16);
    uint16_t my_le16toh(uint16_t le16);
    
    uint32_t my_htobe32(uint32_t h32);
    uint32_t my_htole32(uint32_t h32);
    uint32_t my_be32toh(uint32_t be32);
    uint32_t my_le32toh(uint32_t le32);
    
    uint64_t my_htobe64(uint64_t h64);
    uint64_t my_htole64(uint64_t h64);
    uint64_t my_be64toh(uint64_t be64);
    uint64_t my_le64toh(uint64_t le64);
    
    #endif
    

    myendian.c

    #include "myendian.h"
    
    union swab16
    {
        uint16_t v;
        uint8_t b[2];
    };
    
    union swab32
    {
        uint32_t v;
        uint8_t b[4];
    };
    
    union swab64
    {
        uint64_t v;
        uint8_t b[8];
    };
    
    static uint16_t xbe16(uint16_t x)
    {
        union swab16 s;
    
        s.b[0] = (x >> 8) & 0xffu;
        s.b[1] = x & 0xffu;
        return s.v;
    }
    
    static uint16_t xle16(uint16_t x)
    {
        union swab16 s;
    
        s.b[0] = x & 0xffu;
        s.b[1] = (x >> 8) & 0xffu;
        return s.v;
    }
    
    static uint32_t xbe32(uint32_t x)
    {
        union swab32 s;
    
        s.b[0] = (x >> 24) & 0xffu;
        s.b[1] = (x >> 16) & 0xffu;
        s.b[2] = (x >> 8) & 0xffu;
        s.b[3] = x & 0xffu;
        return s.v;
    }
    
    static uint32_t xle32(uint32_t x)
    {
        union swab32 s;
    
        s.b[0] = x & 0xffu;
        s.b[1] = (x >> 8) & 0xffu;
        s.b[2] = (x >> 16) & 0xffu;
        s.b[3] = (x >> 24) & 0xffu;
        return s.v;
    }
    
    static uint64_t xbe64(uint64_t x)
    {
        union swab64 s;
    
        s.b[0] = (x >> 56) & 0xffu;
        s.b[1] = (x >> 48) & 0xffu;
        s.b[2] = (x >> 40) & 0xffu;
        s.b[3] = (x >> 32) & 0xffu;
        s.b[4] = (x >> 24) & 0xffu;
        s.b[5] = (x >> 16) & 0xffu;
        s.b[6] = (x >> 8) & 0xffu;
        s.b[7] = x & 0xffu;
        return s.v;
    }
    
    static uint64_t xle64(uint64_t x)
    {
        union swab64 s;
    
        s.b[0] = x & 0xffu;
        s.b[1] = (x >> 8) & 0xffu;
        s.b[2] = (x >> 16) & 0xffu;
        s.b[3] = (x >> 24) & 0xffu;
        s.b[4] = (x >> 32) & 0xffu;
        s.b[5] = (x >> 40) & 0xffu;
        s.b[6] = (x >> 48) & 0xffu;
        s.b[7] = (x >> 56) & 0xffu;
        return s.v;
    }
    
    uint16_t my_htobe16(uint16_t h16)
    {
        return xbe16(h16);
    }
    
    uint16_t my_htole16(uint16_t h16)
    {
        return xle16(h16);
    }
    
    uint16_t my_be16toh(uint16_t be16)
    {
        return xbe16(be16);
    }
    
    uint16_t my_le16toh(uint16_t le16)
    {
        return xle16(le16);
    }
    
    uint32_t my_htobe32(uint32_t h32)
    {
        return xbe32(h32);
    }
    
    uint32_t my_htole32(uint32_t h32)
    {
        return xle32(h32);
    }
    
    uint32_t my_be32toh(uint32_t be32)
    {
        return xbe32(be32);
    }
    
    uint32_t my_le32toh(uint32_t le32)
    {
        return xle32(le32);
    }
    
    uint64_t my_htobe64(uint64_t h64)
    {
        return xbe64(h64);
    }
    
    uint64_t my_htole64(uint64_t h64)
    {
        return xle64(h64);
    }
    
    uint64_t my_be64toh(uint64_t be64)
    {
        return xbe64(be64);
    }
    
    uint64_t my_le64toh(uint64_t le64)
    {
        return xle64(le64);
    }
    

    Test harness: myendiantest.c

    #include <stdio.h>
    #include <stdint.h>
    #include <inttypes.h>
    #include "myendian.h"
    
    #define TEST(n, fn, v) \
        printf("%s(%#" PRIx##n ") = %#" PRIx##n "\n", #fn, (v), (fn)(v))
    
    int main(void)
    {
        const uint16_t t16 = UINT16_C(0x1234);
        const uint32_t t32 = UINT32_C(0x12345678);
        const uint64_t t64 = UINT64_C(0x123456789abcdef);
    
        TEST(16, my_htobe16, t16);
        TEST(16, my_htole16, t16);
        TEST(16, my_be16toh, t16);
        TEST(16, my_le16toh, t16);
    
        TEST(32, my_htobe32, t32);
        TEST(32, my_htole32, t32);
        TEST(32, my_be32toh, t32);
        TEST(32, my_le32toh, t32);
    
        TEST(64, my_htobe64, t64);
        TEST(64, my_htole64, t64);
        TEST(64, my_be64toh, t64);
        TEST(64, my_le64toh, t64);
    
        return 0;
    }
    

    Output on a little endian system:

    my_htobe16(0x1234) = 0x3412
    my_htole16(0x1234) = 0x1234
    my_be16toh(0x1234) = 0x3412
    my_le16toh(0x1234) = 0x1234
    my_htobe32(0x12345678) = 0x78563412
    my_htole32(0x12345678) = 0x12345678
    my_be32toh(0x12345678) = 0x78563412
    my_le32toh(0x12345678) = 0x12345678
    my_htobe64(0x123456789abcdef) = 0xefcdab8967452301
    my_htole64(0x123456789abcdef) = 0x123456789abcdef
    my_be64toh(0x123456789abcdef) = 0xefcdab8967452301
    my_le64toh(0x123456789abcdef) = 0x123456789abcdef
    

    Output on a big endian system (expected, but not tested by me):

    my_htobe16(0x1234) = 0x1234
    my_htole16(0x1234) = 0x3412
    my_be16toh(0x1234) = 0x1234
    my_le16toh(0x1234) = 0x3412
    my_htobe32(0x12345678) = 0x12345678
    my_htole32(0x12345678) = 0x78563412
    my_be32toh(0x12345678) = 0x12345678
    my_le32toh(0x12345678) = 0x78563412
    my_htobe64(0x123456789abcdef) = 0x123456789abcdef
    my_htole64(0x123456789abcdef) = 0xefcdab8967452301
    my_be64toh(0x123456789abcdef) = 0x123456789abcdef
    my_le64toh(0x123456789abcdef) = 0xefcdab8967452301