将类指针转换为char指针(不安全)

时间:2015-11-05 12:10:34

标签: c++ pointers unsafe

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

所以,对于代码。为了尝试这个,我创建了一个名为Test的课程:

class Test
{
public:
    char* Allapoto = "AAaaAAaA\0";
    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的部分因为我知道它们起作用所以它们在这里并不重要。我运行它,我想从整个类中的值获取十六进制值(以字节为单位)。 我使用以下代码在程序的主要功能(这是一个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,我之前在较大的一个(第一次测试)中见过它们。如果我查看类结构,我会看到我在之前放了一个bool last和一个int。因此01必须是我的bool,因为bool是1个字节并且它也设置为true,然后在此之前,我声明了一个int。一个int是32位或4个字节,在这里我看到01 04 00 00.然后我们有了char,它在int之前。我总是完成变量并传入一个指向它的指针。现在我想做一个char,然后传入一个char指针。在这种情况下,第一个字符是&#39; A&#39;。当我们查看控制台输出时,我们可以看到它显示41,你可能会问为什么它是41?以及它的十六进制,十六进制中的41是十进制的65,这是A的ascii值。

但现在问我的问题。

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

  2. 如果我们查看第一个输出,并想到问题1,为什么不写在那里的字符,在这种情况下是41?

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

  4. 还有另一种做十六进制哑的方法吗?我想要两个自定义代码,如果有的话,可能需要标准库中的一个函数。

  5. 由于

1 个答案:

答案 0 :(得分:1)

似乎搞得一团糟的是,对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. 如果我们查看char值之前的那个:00 00。为什么不是第一个输出中的那个?
  2.   
<00> 00 00是第一行的一部分,一切都可以。

  
      
  1. 如果我们查看第一个输出,并想到问题1,为什么不写在那里的字符,在这种情况下41?
  2.   

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

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

是的,你是对的。

  
      
  1. 还有另一种方法可以做一个十六进制的哑巴吗?我想要两个自定义代码,如果有的话,可能需要标准库中的一个函数。
  2.   

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

您可以做一些改进。首先,您应该使用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) << " ";
}