将 class 指针转换为字符指针(不安全)

Turn a class pointer into a char pointer (unsafe)

我正在制作一种编程语言。我以前做过几次,但这次我想做得更好,在开发时使用更多的技术。其中之一是我使用了 2 个定义的预处理器,_DEBUG(由我制作,我使用 _ 所以它不会与 Visual Studio 已经定义的混淆,DEBUG)和 _DEBUG_VARS。当我有 _DEBUG = 1 时,我想做一些调试,当我有 _DEBUG_VARS = 1 时,我想做 Var 转储等。其中之一是十六进制转储。我敢打赌标准库中已经有一个,但我想要我自己的。我希望它工作的方式是,我传递一个指向任何 class 的指针(我使用模板 <class T_HEX> 使其工作。然后它会将我输入的 T_HEX* 转换为一个 char*,然后获取 T_HEX 的大小,循环遍历从 char* 开始的所有字节(记住 char* 是 RAM 中 char 所在的位置)。然后我会写那个字节用 2 个十六进制数字输出。我知道这真的不安全,我编码的方式是当我做 _DEBUG_VARS = 1 时,它会创建那些函数,当我做 _DEBUG_VARS = 0 时,这些函数被替换为空定义,如果使用,将在编译时替换为空定义。因为它不安全,我只会在开发过程中使用它。发布版本不会有这个。

所以,对于代码。为了尝试这个,我制作了一个名为 Test:

的 class
class Test
{
public:
    char* Allapoto = "AAaaAAaA[=11=]";
    int Banana = 1025;
    bool Apple = true;
};

注意我这里没有函数,这是因为我希望在使 HexDump 工作时它很简单。 然后 HexDump 自行运行:

int DEBUG_HexLineCounter = 0;
#define H_D_CUT 10
#define H_D_L() (DEBUG_HexLineCounter % H_D_CUT > 0)
#define H_D_NL() ((++DEBUG_HexLineCounter % H_D_CUT) == 0)

template <class T_HEX>
void HexDump(T_HEX* var)
{
    char* ptr = reinterpret_cast<char*>(var);
    char* off_ptr = NULL;

    int size = sizeof(*var);
    for (int i = 0; i < size; i++)
    {
        off_ptr = (ptr + i);
        char c = *off_ptr;

        HexDump(&c);
    }
    if (H_D_L())
        std::cout << std::endl;
}

void HexDump(char* c)
{
    char _char = *c;
    char ch = _char / 0x10;
    char cl = _char % 0x10;

    std::cout << std::hex << static_cast<int>(ch) << std::hex << static_cast<int>(cl) << " ";
    if (H_D_NL())
        std::cout << std::endl;
}

我省略了带有 _DEBUG 和 _DEBUG_VARS 的部分,因为我知道它们有效,所以它们在这里并不重要。我运行这个,我想从整个class中的值中得到以字节为单位的十六进制值。 我 运行 在程序的主要功能(这是一个 Win32 控制台应用程序)中使用此代码:

Test test;
HexDump<Test>(&test);

这导致了输出:

18 5e 17 01 01 04 00 00 01 00

对我来说,这并没有我想要的那么清楚。所以我添加了这段代码:

HexDump<char>(test.Allapoto);
HexDump<int>(&test.Banana);
HexDump<bool>(&test.Apple);

所以它现在看起来像这样:

Test test;
HexDump<Test>(&test);
HexDump<char>(test.Allapoto);
HexDump<int>(&test.Banana);
HexDump<bool>(&test.Apple);

我做了运行这个,这次我得到了更多有趣的东西:

18 5e 17 01 01 04 00 00 01 00
00 00
41
01 04 00 00
01

所以在这之后,我想,嗯,一些熟悉的数字,一些我以前见过的。 第一件事 01 04 00 00 和 01,我之前在更大的(第一次测试)中见过它们。如果我查看 class 结构,我发现我在最后放了一个 bool,在它之前放了一个 int。所以 01 一定是我的 bool,因为 bool 是 1 个字节,它也被设置为 true,然后在此之前,我声明了一个 int。一个 int 是 32 位或 4 个字节,在这里我看到 01 04 00 00。然后我们有 char,它在 int 之前。我总是完成变量并传递一个指向它的指针。现在我想做一个字符,并传入一个字符指针。在这种情况下,第一个字符是 'A'。我们看控制台输出,可以看到显示的是41,你可能会问为什么是41?好吧,它是十六进制的,十六进制的 41 是十进制的 65,这是 A 的 ascii 值。

但现在回答我的问题。

  1. 如果我们看char值之前的那个:00 00。为什么第一个输出的不是那些?

  2. 如果我们查看第一个输出,并想到问题 1,为什么字符没有写在那里,在本例中为 41?

  3. 现在它不是 41,我们还可以看到其余的 char*(字符串)也不存在。也许那些 18 5e 17 01 是指向 char* 字符串的指针,对吗?

  4. 有没有其他方法来做十六进制哑?我想要自定义代码,也许如果有的话,标准库中的函数。

谢谢

似乎搞砸了的是对 HexDump 的一次调用可能会导致多行。如果您将逻辑更改为在通用 HexDump 末尾始终输出换行符,而从不在专用 HexDump 中输出换行符,则每次调用 HexDump.

都会得到一行

这可能会解决您的一些问题。

没有这些修改我得到输出:

--- &test:
6f 10 40 00 00 00 00 00 01 04 
00 00 01 00 00 00 
--- test.Allapoto:
41 
--- &test.Banana:
01 04 00 
00 
--- &test.Apple:
01 

通过修改换行符处理,我得到:

--- &test:
6f 10 40 00 00 00 00 00 01 04 00 00 01 00 00 00 
--- test.Allapoto:
41 
--- &test.Banana:
01 04 00 00 
--- &test.Apple:
01 
  1. If we look at the one before the char value: 00 00. Why isn't those in the first output?

00 00 是第一行的一部分,这里一切正常。

  1. If we look in the first output, and think of question 1, why isn't the char written there, in this case 41?

41 是该行的第一个字符,而在您存储指针的结构中。

  1. Now that it isn't 41 there, we can also see that the rest of the char* (string) isn't there either. Maybe those 18 5e 17 01 is a pointer to the char* string, am I right?

是的,你是对的。

  1. Is there another way to do a hex dumb? I want both custom code, and maybe if there is, a function in the standard library.

您必须意识到执行十六进制转储的任何方式都将跨越标准中定义的边界。您将不得不依赖一些实现定义的行为,并且在某种程度上,未定义的行为不会导致鼻恶魔。大多数编译器可能会在这里正常运行以允许十六进制转储。

您可以做一些改进。首先,您可能应该使用 unsigned char 而不是 char 以保证在将字节转换为十六进制时不会获得符号扩展。

其次你应该改进换行逻辑。您可能应该将其限制在通用 HexDump 函数中,并将计数器设为局部变量。例如:

template <class T_HEX>
void HexDump(T_HEX* var)
{
    unsigned char* ptr = reinterpret_cast<unsigned char*>(var);
    unsigned char* off_ptr = NULL;

    int size = sizeof(*var);
    for (int i = 0; i < size; i++)
    {
        off_ptr = (ptr + i);
        unsigned char c = *off_ptr;

        if( i && i%8 == 0 )
            std::cout << std::endl;
        HexDump(&c);
    }
    std::cout << std::endl;
}

void HexDump(unsigned char* c)
{
    unsigned char _char = *c;
    unsigned char ch = _char / 0x10;
    unsigned char cl = _char % 0x10;

    std::cout << std::hex << static_cast<int>(ch) << std::hex <<     static_cast<int>(cl) << " ";
}