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>
定义。)
同时检查较新的字节顺序转换函数 htobe16
、htole16
、be16toh
、le16toh
、htobe32
、htole32
、[ =31=、le32toh
、htobe64
、htole64
、be64toh
和 le64toh
声明者:
#define _BSD_SOURCE
#include <endian.h>
这些在主机字节顺序和 little-endian 字节顺序之间转换,或在主机字节顺序和 big-endian 字节顺序之间转换,并在 uint16_t
、uint32_t
或 uint64_t
值,取决于函数名称。
如果您的系统上没有提供与那些 byte-order 转换函数等效的 non-optimized,但可移植(在支持 uint16_t
、uint32_t
和uint64_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
我必须用整数在 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>
定义。)
同时检查较新的字节顺序转换函数 htobe16
、htole16
、be16toh
、le16toh
、htobe32
、htole32
、[ =31=、le32toh
、htobe64
、htole64
、be64toh
和 le64toh
声明者:
#define _BSD_SOURCE
#include <endian.h>
这些在主机字节顺序和 little-endian 字节顺序之间转换,或在主机字节顺序和 big-endian 字节顺序之间转换,并在 uint16_t
、uint32_t
或 uint64_t
值,取决于函数名称。
如果您的系统上没有提供与那些 byte-order 转换函数等效的 non-optimized,但可移植(在支持 uint16_t
、uint32_t
和uint64_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