memset char * 与 Integer

memset char * with Integer

我必须用整数在 char * 中存储 4 个字节。

例如我有一个整数int i = 3276854 (0x00320036)和一个char header[54] = {0}。我必须在 header + 2 处写 i,就好像我将内存从 header[2] 打印到 header[6],我得到:

0032 0036

我试过这个:

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

但它似乎只将最后一个字节放入 header,我得到:

0036 0000

我也试过:

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

但是它用 i 的最后一个字节填充每个字节,我得到:

3636 3636

我也试过像那样使用二进制掩码:

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);

我得到:

3600 0000.

所以我不知道如何获得我的 0032 0036,或者至少 3600 3200(也许其中有小端和大端,因为我 运行 它在 MacOS 下,它是 big endian)。

memset 用常量字节值填充内存。第二个参数(int 类型)转换为 unsigned char 值。

您可以这样使用 memcpy

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

但是,这取决于您要实现的目标。如果 header 需要整数采用特定格式,您可能需要以某种方式转换该值。例如需要取值big-endian(在几个Internet协议中也称为"network byte order"),可以用htonl函数转换:

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

htonl函数由#include <arpa/inet.h>定义。)

同时检查较新的字节顺序转换函数 htobe16htole16be16tohle16tohhtobe32htole32、[ =31=、le32tohhtobe64htole64be64tohle64toh 声明者:

#define _BSD_SOURCE
#include <endian.h>

这些在主机字节顺序和 little-endian 字节顺序之间转换,或在主机字节顺序和 big-endian 字节顺序之间转换,并在 uint16_tuint32_tuint64_t 值,取决于函数名称。

如果您的系统上没有提供与那些 byte-order 转换函数等效的 non-optimized,但可移植(在支持 uint16_tuint32_tuint64_t) 可以使用函数:

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);
}

测试工具: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;
}

在小端系统上的输出:

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

big endian 系统上的输出(预期,但未经我测试):

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

您可以使用 memcpy,但这会使您的代码依赖于 CPU 的底层字节顺序。我不认为那是你想要的。

我的看法是,您想转换为任何数据通信协议的 网络字节序 不考虑 CPU 字节序

实现这一目标的唯一方法是位移位。字节顺序取决于目标网络字节顺序:

void u32_to_big_endian (uint8_t* dst, const uint32_t src)
{
  dst[0] = (uint8_t) ((src >> 24) & 0xFFu);
  dst[1] = (uint8_t) ((src >> 16) & 0xFFu);
  dst[2] = (uint8_t) ((src >>  8) & 0xFFu);
  dst[3] = (uint8_t) ((src >>  0) & 0xFFu);
}

void u32_to_little_endian (uint8_t* dst, const uint32_t src)
{
  dst[3] = (uint8_t) ((src >> 24) & 0xFFu);
  dst[2] = (uint8_t) ((src >> 16) & 0xFFu);
  dst[1] = (uint8_t) ((src >>  8) & 0xFFu);
  dst[0] = (uint8_t) ((src >>  0) & 0xFFu);
}

在这些函数中,CPU 字节序是什么并不重要。您可以忘记 memcpy() 和非标准字节顺序转换函数。完整示例:

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

void u32_to_big_endian (uint8_t* dst, const uint32_t src)
{
  dst[0] = (uint8_t) ((src >> 24) & 0xFFu);
  dst[1] = (uint8_t) ((src >> 16) & 0xFFu);
  dst[2] = (uint8_t) ((src >>  8) & 0xFFu);
  dst[3] = (uint8_t) ((src >>  0) & 0xFFu);
}

void u32_to_little_endian (uint8_t* dst, const uint32_t src)
{
  dst[3] = (uint8_t) ((src >> 24) & 0xFFu);
  dst[2] = (uint8_t) ((src >> 16) & 0xFFu);
  dst[1] = (uint8_t) ((src >>  8) & 0xFFu);
  dst[0] = (uint8_t) ((src >>  0) & 0xFFu);
}


int main(void)
{
  uint32_t i = 0x00320036u; 
  uint8_t header[54] = {0};

  u32_to_little_endian(&header[2], i);
  for(size_t i=0; i<6; i++)
  {
    printf("%.2x ", (unsigned int)header[i]);
  }
}

输出,包括前 2 个字节为零:

00 00 36 00 32 00