7

我想知道是否可以按位而不是字节来做 memcpy

我正在为带有 VLAN 标记的以太网帧编写 C 代码,其中我需要为 VLAN 标头属性(PCP-3bits、DEI-1bit、VID-12bits)填充不同的值。

我怎样才能对这些位进行 memcpy,或者以任何其他方式将值填充到这些位中的属性。

提前致谢 !

4

4 回答 4

7

不。位是不可寻址的(这意味着无法直接从内存中读取它们,只能读取它们。它们没有地址。只有字节有地址)。

您需要读取包含您感兴趣的位的字节或字并自己进行屏蔽

于 2013-06-26T12:59:17.693 回答
2

我已经为客户端完成了帧的 802.1Q VLAN 标记,他们只有 802.3 以太网帧,但由于安装了新的 VLAN 感知交换机,因此希望迁移到 802.1Q。

首先,您不能复制位。我们已经使用 memcpy 以字节为单位复制了标签。

插图(有关字段的描述,请参阅 Wikipedia):-

VLAN 标记 = 4 字节;由 TPID(2 字节)和 TCI(2 字节)组成。

TPID 很简单,始终为 0x8100,表示带有 VLAN 标记的帧。

TCI由PCP-3bits、DEI-1bit、VID-12bits组成。将 TCI 分解为半字节,即 4 位。默认情况下,半字节(PCP+DEI) = 0x0 假设优先级被禁用并且 DEI = 0。剩余的 3 个半字节(12 位)用于 VLAN-ID 本身。假设您想为 VLAN-ID = 123 标记一个帧。在十六进制中,这将是 = 0x07B。

将半字节组合在一起,您就有了 2 字节的 TCI 字段,现在可以视为 0x007B。

然后,您可以执行以下操作。(代码未编译)

unsigned short int vlanTPID, vlanTCI;
unsigned char     *dest, *src;

// Set the VLAN Tag
vlanTPID = 0x8100;
vlanTCI  = 0x007B;

// Pointer to the TPID position of ethernet frame
dest = &vlanTagPosition;
src = &vlanTPID;
memcpy(dest, src, sizeof(vlanTPID));

// Increment dest pointer by 2 bytes to insert TCI in the ethernet frame
dest += 2;
src = &vlanTCI;
memcpy(dest, src, sizeof(vlanTCI));
于 2013-11-10T07:26:13.177 回答
0

如果需要填充字段,可以使用带有 的C位字段struct,如下所示:

struct box_props {
    unsigned first  : 1;
    unsigned second : 3;
    unsigned : 4;
};

例如,其中1表示该字段的长度为 1 位。最后一个(未命名的)字段表示:4 位填充。

定义它并读取字段structmemcpy就好像它们在哪里一样unsigned。写作也一样。

注意:始终填充到整数字节,否则memcpy可能会产生不良影响。

于 2013-06-26T12:59:11.470 回答
0

只是实现复制任何任意位集。最后一个实现是tacklelib库的一部分:
https://github.com/andry81/tacklelib
https://github.com/andry81/tacklelib/blob/trunk/include/tacklelib/utility/memory.hpp

优点

  • 按 64 位字复制。
  • memcpy在可以推断的情况下动态使用函数。

缺点

  • 两个缓冲区必须在末尾填充 7 个字节,因此在结束偏移之后的输出缓冲区中的 7 个字节基本上可以被覆盖。如果这些字节不是填充缓冲区结束,则可以通过将此部分单独保存为 64 位字加掩码并在函数调用后复制回来来恢复它们。
  • 缓冲区不得重叠。
// Bitwise memory copy.
// Both buffers must be padded to 7 bytes remainder to be able to read/write the last 8-bit block as 64-bit block.
// Buffers must not overlap.
//
FORCE_INLINE void memcpy_bitwise64(uint8_t * to_padded_int64_buf, uint64_t to_first_bit_offset, uint8_t * from_padded_int64_buf, uint64_t from_first_bit_offset, uint64_t bit_size)
{
    assert(bit_size);

    uint64_t bit_offset = 0;

    uint32_t from_byte_offset = uint32_t(from_first_bit_offset / 8);
    uint32_t to_byte_offset = uint32_t(to_first_bit_offset / 8);

    uint32_t remainder_from_bit_offset = uint32_t(from_first_bit_offset % 8);
    uint32_t remainder_to_bit_offset = uint32_t(to_first_bit_offset % 8);

    while (bit_offset < bit_size) {
        if (remainder_to_bit_offset >= remainder_from_bit_offset && (remainder_to_bit_offset || remainder_from_bit_offset)) {
            const uint64_t from_bit_block = *(uint64_t *)&from_padded_int64_buf[from_byte_offset];
            uint64_t & to_bit_block = *(uint64_t *)&to_padded_int64_buf[to_byte_offset];

            const uint32_t to_first_bit_delta_offset = remainder_to_bit_offset - remainder_from_bit_offset;
            const uint64_t to_bit_block_inversed_mask = uint64_t(~0) << remainder_to_bit_offset;

            to_bit_block = ((from_bit_block << to_first_bit_delta_offset) & to_bit_block_inversed_mask) | (to_bit_block & ~to_bit_block_inversed_mask);

            const uint32_t bit_size_copied = 64 - remainder_to_bit_offset;

            bit_offset += bit_size_copied;

            from_first_bit_offset += bit_size_copied;
            to_first_bit_offset += bit_size_copied;

            if (remainder_to_bit_offset != remainder_from_bit_offset) {
                from_byte_offset += 7;
                to_byte_offset += 8;

                remainder_from_bit_offset = 8 - to_first_bit_delta_offset;
                remainder_to_bit_offset = 0;
            }
            else {
                from_byte_offset += 8;
                to_byte_offset += 8;

                remainder_from_bit_offset = 0;
                remainder_to_bit_offset = 0;
            }
        }
        else if (remainder_to_bit_offset < remainder_from_bit_offset) {
            const uint64_t from_bit_block = *(uint64_t *)&from_padded_int64_buf[from_byte_offset];
            uint64_t & to_bit_block = *(uint64_t *)&to_padded_int64_buf[to_byte_offset];

            const uint32_t to_first_bit_delta_offset = remainder_from_bit_offset - remainder_to_bit_offset;
            const uint64_t to_bit_block_inversed_mask = uint64_t(~0) << remainder_to_bit_offset;

            to_bit_block = ((from_bit_block >> to_first_bit_delta_offset) & to_bit_block_inversed_mask) | (to_bit_block & ~to_bit_block_inversed_mask);

            const uint32_t bit_size_copied = 64 - remainder_from_bit_offset;

            bit_offset += bit_size_copied;

            from_first_bit_offset += bit_size_copied;
            to_first_bit_offset += bit_size_copied;

            from_byte_offset += 8;
            to_byte_offset += 7;

            remainder_from_bit_offset = 0;
            remainder_to_bit_offset = (8 - to_first_bit_delta_offset);
        }
        // optimization
        else {
            const uint64_t bit_size_remain = bit_size - bit_offset;
            const uint32_t byte_size_remain = uint32_t(bit_size_remain / 8);

            if (byte_size_remain + 1 > 8) {
                memcpy(to_padded_int64_buf + to_byte_offset, from_padded_int64_buf + from_byte_offset, byte_size_remain + 1);
            }
            // optimization
            else {
                *(uint64_t *)&to_padded_int64_buf[to_byte_offset] = *(uint64_t *)&from_padded_int64_buf[from_byte_offset];
            }

            break;
        }

        assert(from_byte_offset == uint32_t(from_first_bit_offset / 8));
        assert(remainder_from_bit_offset == uint32_t(from_first_bit_offset % 8));

        assert(to_byte_offset == uint32_t(to_first_bit_offset / 8));
        assert(remainder_to_bit_offset == uint32_t(to_first_bit_offset % 8));
    }
}
于 2022-03-04T06:09:05.400 回答