【问题标题】:Is there any difference between casting pointer to int and to character? in C++将指针转换为 int 和字符之间有什么区别吗?在 C++ 中
【发布时间】:2019-08-06 08:50:08
【问题描述】:
#include <iostream>

char** make2D(const int dim1, const int dim2)
{
    char* toAlloc;
    const int size = (dim1 * dim2) + dim2;
    toAlloc = new char[size];

    for(int i = 0; i < dim2; i++)
    {
        toAlloc[i] = reinterpret_cast<char>(&toAlloc[(dim2 + (dim1 * i))]);
    }

    return reinterpret_cast<char**>(toAlloc);
}

int main(void)
{
    int dim1 = 8;
    int dim2 = 10;
    char** array2D = make2D(dim1, dim2);

    for (int i = 0; i < dim2; ++i)
    {
        array2D[i][i % dim1] = i + 100; // << Crash
    }

    return 0;
}

我试图通过一次分配来分配二维数组。 因此,我的算法是,前 10 个(在此代码中为 dim2)项具有指向每行第一项的指针。

当我通过指向'int'的指针尝试这个时,

int** make2D(const int dim1, const int dim2)
{
    int* toAlloc;
    const int size = (dim1 * dim2) + dim2;
    toAlloc = new int[size];

    for(int i = 0; i < dim2; i++)
    {
        toAlloc[i] = reinterpret_cast<int>(&toAlloc[(dim2 + (dim1 * i))]);
    }

    return reinterpret_cast<int**>(toAlloc);
}

int main(void)
{
    int dim1 = 8;
    int dim2 = 10;

    int** array2D = make2D(dim1, dim2);

    for (int i = 0; i < dim2; ++i)
    {
        array2D[i][i % dim1] = i + 100;
    }

    return 0;
}

它工作正常,但是当我在 char 中执行此操作时,它会在上面代码的注释行中崩溃。

我想到崩溃是当我执行reinterpret_cast 时,由于指针(8 字节)和字符(1 字节)之间的内存大小差距而发生了一些事情。 就像,听起来很荒谬......将指针(8byte)更改为int(4byte)很好,但是当我更大幅度地转换(8byte到1byte)时,它会导致一些问题......

我不知道为什么 char 不起作用但 int 起作用。 您能给 char case 提供一些建议吗?

【问题讨论】:

  • 那个代码错的地方太多了。 char 通常是 8 位,一个字节。在 32 位平台上,指针通常为 32 位。您如何能够将 32 位数据放入 8 位值中?而在 64 位系统上,指针通常是 64 位,是 char 大小的八倍。
  • 更不用说toAlloc 不是一个指针数组,这样使用它是错误的(不管它是否起作用)。
  • reinterpret_cast 是一个危险信号。在您认为需要reinterpret_cast 的 99% 的情况下,您做错了什么
  • std::vectorstd::array 用于动态/固定大小的数组,并围绕2 个或更多维度包装一些索引映射。其他任何事情都不必要地复杂

标签: c++ memory-management allocation reinterpret-cast


【解决方案1】:

要回答这个问题,是的,有一个很大的区别,在许多平台上,指针可能适合 int,而在极少数平台上,它适合 char。在 64 位的现代 PC 上,none 是存储指针的安全方法。

如果大小是静态的,请使用 vectorarray 等容器。 尝试类似:

array<array<T, dim2>, dim1> variable{};

如果你真的想要一个 T 类型的二维数组;因为您似乎需要一个指针数组,请尝试以下操作:

array<array<T *, dim2>, dim1> variable{};

这将注意为您的平台创建一个适当类型的数组来存储指针,无论指针实际有多大,显然您应该将 T 替换为您想要指向的数据的正确类型,这个将确保指针数学为您正确完成。 数组类型将在编译时计算它们的大小,如果您需要动态大小,您应该使用向量,在分配后对向量和所有子向量调用 resize 以确保您在尽可能少的传递中分配所有内存。

也请不要使用 reinterpret_cast 或 c-style casts,除非你非常清楚自己在做什么,否则这是灾难的根源。

不知道你在读什么书或谁教你 C++,但请改变你的知识来源。

不鼓励使用原始的拥有指针,而且您使用它们的方式在很多方面都是错误的。 切勿将指针存储在除指针类型之外的任何内容中。即使在纯 C 中,如果您需要转换,您至少应该转换为 void *。

如果您真的想直接存储/传递指针,请阅读unique_ptrshared_ptr

如果你坚持对容器使用原始指针,请尝试使用地址清理器、内存清理器等清理器构建代码(这些至少被 clang 和 gcc 支持,现在可能更多的编译器支持)

【讨论】:

  • @user463035818 虽然我同意你的观点,但我认为不应该鼓励学习语言的人使用它们,因为他们会掉入陷阱,比如将它们强制转换为整数
  • @xception reinterpret_cast 可能是应该保留的内容,而不是指针。
  • 是的,有一个巨大的危险,现在大多数 PC 都是 64 位的,而它们上的 int 是 32 位的,如果你关心移植到其他平台,那也是一个巨大的痛苦,更不用说如果您想对其进行数学运算,那将是一场灾难
  • 按照建议添加了关于 reinterpret_cast 的警告,你是对的,还更新了文本以读取原始拥有指针,这也是正确的
【解决方案2】:

问题是对象大小的“不兼容”:

  • sizeof(char)1
  • sizeof(int) 通常是 48(但至少是 2)。
  • sizeof(T*) 通常为48std::uintp_t 可以保持void* 的值,int 则不需要(char 则更少)。

您无法将void* 安全地存储到charint。碰巧它适用于 int,但它不是可移植的。

reinterpret_cast 通常是错误的工具。

更简单的方法是创建一个class Matrix,使用std::vector&lt;T&gt; 和访问器来修复索引。 (您甚至可能有代理以允许 m[2][3] 语法)。

拥有原始指针,您需要新的展示位置,并提供正确的删除器...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-12
    • 1970-01-01
    • 2012-04-07
    • 1970-01-01
    • 2017-06-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多