【问题标题】:C++ type casting with pointers使用指针进行 C++ 类型转换
【发布时间】:2012-07-29 10:52:38
【问题描述】:

我来自 C# 和 Java 的背景,我似乎无法理解 C++ 中的指针转换意味着什么。

例如:

int x = 1;
char c = *((char*)&x);

它有什么作用?有什么用?

【问题讨论】:

  • 在 C++ 中你应该避免强制转换。强制转换是一种告诉编译器“不,不,你会认为这是错误的,但我确信我是对的”的方式。尽管在 C++ 中始终使编译器正确总是更好。强制转换是一种抑制编译器错误的方法。因此,基本上,询问针对特定目的的铸造比一般铸造更具建设性。应该完全避免在 C++ 中使用您的两个示例。
  • 您想知道关于使用指针进行一般转换还是从您的示例中看起来转换为char *char const * 之间的区别?
  • 我编辑了帖子,现在我想应该更清楚了。
  • 你的例子都没有编译,所以它们没有意义。
  • 编辑后代码无法编译:应该是char c = *((char*)x);

标签: c++ pointers casting


【解决方案1】:

在您的两个示例中,您都犯了错误,导致代码无法编译。所以我假设您正在尝试执行以下操作:

int x = 1;
char c = *((char*)&x);

根据您的架构,c 现在将具有x 的最低或最高有效字节的值。在这个例子中,这可能是 0 或 1(这实际上可以用来检测字节顺序)。

您的第二个示例不起作用,因为您试图忽略 const 导致非法操作/错误转换(这也称为“const 正确性”)。

编辑:关于您对“这是什么意思?”的评论:

在表达式中: &somevariable 将返回somevariable 的地址。 *somevariable 将假定somevariable 的内容是实际值的地址,然后返回。

在声明中: datatype 是一个普通的变量/对象。这是“按值”传递的。 datatype& 是一个参考。这与 Java/C# 中的普通变量完全一样,并且通过引用传递。 datatype* 是一个指针。这仅包含实际值所在的地址(见上文),并且本质上也是通过引用传递的。

实际转换的工作方式与 Java/C# 非常相似,但指针就是这样:它们指向实际值的位置。虽然这可能会让您感到困惑,但 C/C++ 中的指针的工作方式与 Java/C# 中使用的标准变量/引用非常相似。

看看这个:

MyClass x; // object of MyClass
MyClass *x; // pointer to an object of MyClass - the actual value is undefined and trying to access it will most likely result in an access violation (due to reading somewhere random).
MyClass *x = 0; // same as above, but now the default value is defined and you're able to detect whether it's been set (accessing it would essentially be a "null reference exception"; but it's actually a null pointer).
MyClass &x = MyClass(); // creating a new reference pointing to an existing object. This would be Java's "MyClass x = new MyClass();"

【讨论】:

    【解决方案2】:

    C++ 中的强制转换与 Java 中的强制转换一样,不涉及指针。

    int x = 1;
    char c = (char) x; // Lose precision
    

    但是,你在这里做什么:

    int x = 1;
    char *c = (char *)x;
    

    告诉编译器x 的值是一个字符的地址。相当于

    char *c;
    c = 1; // Set the address of c to 0x0000000000000001
    

    您需要这样做的次数很少。

    【讨论】:

      【解决方案3】:

      C++ 中有两个根本不同的概念,它们有时都被称为“转换”:一个是转换,一个是重新解释

      转换会创建一个与现有对象具有“相同值”但类型不同的新对象。以下是一些示例:

      示例 1:类型提升

      // 1a: promote int to double to get the correct type of division
      
      int numerator = rand(), denominator = rand();
      double d = double(numerator) / double(denominator); 
      

      // 1b: convert int to double to achieve a particular argument deduction
      
      int n;
      template <typename T> void do_numeric_stuff(T x) { /* ... */ }
      
      do_numeric_stuff(double(n));
      

      示例 2:派生到基础的转换

      struct B { }; struct D : B { };
      D x;
      
      D * p = &x;  // pointer to x
      B * q = p;   // implicit conversion; may change the value!
      


      另一方面,重新解释允许我们将一个变量视为另一个变量。唯一正确和有用的应用程序是序列化,以一种或另一种形式。

      示例 3:序列化

      std::ofstream file("output.bin");    // output file
      char large_buffer[HUGE];             // in-memory buffer
      
      unsigned int n = get_data();
      
      char const * p = reinterpret_cast<char const *>(&n);
      file.write(p, p + sizeof n);                         // write the bytes of `n`
      std::copy(p, p + sizeof n, large_buffer);            // ditto
      
      std::copy(large_buffer + 17, large_buffer + 17 + sizeof n,
                reinterpret_cast<char *>(&n));   // repopulate `n` from buffer
      

      标准规定,通过不正确类型的指针访问对象是未定义的行为(也称为“类型双关语”)。虽然可以将对象指针存储在void* 中,然后将其转换回来并使用它,但可以将浮点数视为整数等。 唯一可以接受的方式来访问一个对象,就好像它是另一个对象是我演示的那样,即将T 类型的对象当作一个数组char[sizeof(T)] 处理——也就是说,你是允许访问每个对象的底层二进制表示。

      【讨论】:

        【解决方案4】:

        你应该尽量避免像 (char*) 这样的 c 类型转换。如果您真的需要进行类型转换,请查看dynamic_caststatic_castreinterpret_cast

        但如前所述,您几乎不需要强制转换。

        在这里查看更多信息: http://www.cplusplus.com/doc/tutorial/typecasting/

        http://www.parashift.com/c++-faq/static-typing-and-cpp.html

        http://www.parashift.com/c++-faq-lite/print-char-or-ptr-as-number.html

        【讨论】:

          【解决方案5】:

          我很久以前用过这个习惯用法来访问指定地址的硬件,在自定义 IO 板上。因此,例如在 PIC(可编程中断控制器)处写入以重置某些标志(虚构代码):

          #define PIC_LOC 0x1000
          #define PIC_ENABLE_PORT *((char*)(PIC_LOC+0x10))
          #define BIT_ENABLE (1 << 3)
          
          ...
          PIC_ENABLE_PORT |= BIT_ENABLE;
          ...
          

          【讨论】:

            猜你喜欢
            • 2021-08-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-09-20
            • 2017-10-06
            • 1970-01-01
            • 2020-11-17
            相关资源
            最近更新 更多