在结构和模板中试验联合和位域 [英] Experimenting with Unions and Bitfields within a structures and templates

查看:25
本文介绍了在结构和模板中试验联合和位域的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了更好地处理和理解位域、联合和结构的字节对齐是如何工作的,我模拟了一个模板寄存器结构.

To get a better handle and understanding of how bitfields, unions, and the byte alignment of structures work, I'm simulating a template Register structure.

我的注册要求如下:

  • 寄存器的默认大小或宽度为 8 位或 1 字节
  • 较大的寄存器必须是 8 的倍数
  • 寄存器的大小小于或等于 64 位或 8 个字节.

我有一组结构,它们以级联效果相互构建,从字节的基本单位到 QWord.

I have a set of structures which build off of each other in a cascading effect starting from the base unit of a Byte down to a QWord.

我的寄存器是模板专业化.

My Registers are template specializations.

这是我目前的代码:

-main.cpp-

#include <iostream>
#include "Register.h"

int main() {
    Register r1;
    r1.value.value_ = 8;

    Register<16> r2;
    r2.value.value_ = 16;

    Register<32> r3;
    r3.value.value_ = 32;

    Register<64> r4;
    r4.value.value_ = 64;

    std::cout << static_cast<std::uint8_t>( r1.value.value_) << "\n";
    std::cout << static_cast<std::uint16_t>(r2.value.value_) << "\n";
    std::cout << static_cast<std::uint32_t>(r3.value.value_) << "\n";
    std::cout << static_cast<std::uint64_t>(r4.value.value_) << "\n";

    return EXIT_SUCCESS;
}

-Register.h-

#pragma once

#include <vector> // include for typedefs below.
typedef std::int8_t  i8;
typedef std::int16_t i16;
typedef std::int32_t i32;
typedef std::int64_t i64;

struct MyByte {
    union {
        i8 value_;
        struct {
            i8 b0 : 1;
            i8 b1 : 1;
            i8 b2 : 1;
            i8 b3 : 1;
            i8 b4 : 1;
            i8 b5 : 1;
            i8 b6 : 1;
            i8 b7 : 1;
        };
    };
};

struct MyWord {        // same as short or i16  
    union {
        i16 value_;
        union {
            MyByte byte_[2];
            struct {
                MyByte b0_;
                MyByte b1_;
            };
        };
    };
};

struct MyDWord {       // same as int or i32
    union {
        i32 value_;

        struct {
            MyWord w0_;
            MyWord w1_;
        };

        union {
            MyByte byte_[4];
            struct {
                MyByte b0_;
                MyByte b1_;
                MyByte b2_;
                MyByte b3_;
            };
        };
    };
};

struct MyQWord {     // same as long or i64
    union {
        i64 value_;
        struct {
            MyDWord d0_;
            MyDWord d1_;
        };
        struct {
            MyWord w0_;
            MyWord w1_;
            MyWord w2_;
            MyWord w3_;
        };
        union { 
            MyByte byte_[8];
            struct {
                MyByte b0_;
                MyByte b1_;
                MyByte b2_;
                MyByte b3_;
                MyByte b4_;
                MyByte b5_;
                MyByte b6_;
                MyByte b7_;
            };
        };
    };
};

template<size_t N = 8>
struct Register {
    MyByte value;
    Register() {
        static_assert(
         ((N % 8) == 0) &&
         (N >= 8) &&
         (N <= 64)

        );
    }
};

template<>
struct Register<16> {
    MyWord value;
    Register() = default;
};

template<>
struct Register<32> {
    MyDWord value;
    Register() = default;
};

template<>
struct Register<64> {
    MyQWord value;
    Register() = default;
};

以上代码在编译器设置为最新草案标准的情况下,在 Visual Studio 2017 中以代码 0 编译、运行和退出.

The above code compiles, runs and exits with a code of 0 in Visual Studio 2017 with the compiler set to the latest draft standard.

现在你已经看到了代码,我在某种程度上理解了位域和联合,但是当我不经常使用它们时,它们会让我有点困惑.我确实知道,尤其是在以组合方式使用它们时,可能会导致代码不可移植,尤其是在不同的编译器、操作系统和架构(字节序)之间.

Now that you have seen the code, I understand bitfields and unions to some degree but when I don't use them all that often they can trip me up a bit. I do know that when using them especially in a combined manner that it can cause the code to not be portable especially across different compilers, operating systems and architectures (endian).

然而,这只是实验性代码,可以很好地复习它们.

However this is just experimental code to practice on them as a good refresher.

我在这里遇到的问题是我的输出.所有高阶寄存器似乎都可以正常工作,我只测试了直接通过最内部的成员变量 value_ 获取它.但是,我从默认或最基本的寄存器中获得了 8 位大小的结果.将值设置为当前状态.我得到这个作为输出:

The issue I'm having here is that of my output. All of the higher order registers seem to be working okay, I have only tested getting it through the inner most member variable value_ directly. However, I am getting results from the default or most basic register the 8 bit sized one. With the values being set as they currently are. I'm getting this as output:

--

16
32
64

如果我将我的主要更改为:

And if I change my main to this:

#include <iostream>
#include "Register.h"

int main() {
    Register r;
    for (i8 i = 0; i < 21; i++) {
        1.value.value_ = i;
        std::cout << static_cast<std::uint8_t>(r.value.value_) << "\n";
    }
    return EXIT_SUCCESS;
}

我在混合输出中发出哔哔声:

I am getting this output with a beep some where in the mix of it:

☺
☻
♥
♦
♣
♠





♂
♀

♫
☼
►
◄
↕
‼
¶

这与 std::int8_t 的定义方式有关吗?它是否基于 char 值类型而不是 int 类型?但是它仍然应该是完整的......如果是这种情况,它是否必须处理联合或位域等中的无符号值?是什么导致 ASCII 符号打印到控制台.

Does this have something to do with how std::int8_t is defined? Is it based on a char value type instead of a int type? It should still be integral though... if this is the case than does it have to deal with unsigned values within unions or bitfields etc.? What is causing the ASCII symbols to print to the console.

推荐答案

它是基于char值类型而不是int类型吗?

Is it based on a char value type instead of a int type?

char *是*整数类型.该标准允许 std::int8_t 成为 char 的 typedef.

char *is* an integer type. The standard allows std::int8_t to be a typedef to char.

std::cout << static_cast<std::uint64_t>(r.value.value_) << "\n";

ftw.

这篇关于在结构和模板中试验联合和位域的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆