【问题标题】:Using reinterpret_cast to return long long from char*使用 reinterpret_cast 从 char* 返回 long long
【发布时间】:2014-07-22 12:16:20
【问题描述】:

我有以下代码:

char* p = "12345";

long long x = *reinterpret_cast<long long*>(p);

我不断收到x 的 228509037105- 我期待 12345。

我做错了什么?

更新:

由于我最初的理解,我错误地问了这个问题。但是,据我后来得知,可以使用reinterpret_cast 从 char 数组中读取 8 个字节!毕竟,无论是位构成的值还是指针,它们在位级别都是一样的!

【问题讨论】:

  • reinterpret_cast 根本不是这样工作的。见reference
  • @BaummitAugen:几乎所有问题,但 C 和 C++ 标签中几乎没有...

标签: c++ bits reinterpret-cast


【解决方案1】:

reinterpret_cast 的指针强制编译器重新解释不同数据类型的内存地址。要将字符串 "12345" 转换为 long long 12345,您需要转换数字:

#include <sstream>

long long str2ll(const char* p) {
    std::sstream ss;
    ss << p;
    long long r;
    ss >> r;
    return r;
}

正如 cmets 上的 chris 所说,在 C++11 中,您可以使用 std::stoll

const char* p = "12345";
long long n = std::stoll(std::string(p));

更新:您可以从 8 个字节的内存中读取 long long,但重新解释为 long long 指针的字符串“12345678”将不是整数 "12345678" 但依赖于endianess of your architecture:

const char* p = "12345678";
long long n = *reinterpret_cast<const long long*>(p);
std::cout << n << std::endl;

这个程序打印40507659919799875053544952156018063160,无论你是在小端还是大端架构上。那是因为:

hex(4050765991979987505) = 0x38 37 36 35 34 33 32 31
hex(3544952156018063160) = 0x31 32 33 34 35 36 37 38

0x38 是 ASCII 数字 8 的十六进制表示。

【讨论】:

  • 好的,我的理解有点错误,因此我问 Q 的方式,但是您仍然可以使用 reinterpret_cast 从 char* 读取 8 个字节(所以我被告知)... .
  • @user997112 当然,您可以使用 reinterpret_cast 读取 8 个字节,问题在于您如何解释它们。我已经更新了答案
【解决方案2】:

您误解了 reinterpret_cast 的用法。请read this documentation page for reinterpret_cast

你的函数的作用如下: char* p = "12345"; 行创建了一个名为 p 的指向字符变量的指针,它指向一个内存区域,该内存区域包含一个用 6 字节 \0x31\0x32\0x33\0x34\0x35\0x00 初始化的常量缓冲区。例如,当您将此变量 p 传递给 printf 时,它会将 p 指向的内存解释为以 null 结尾的字符串,并打印“12345”。

long long x = *reinterpret_cast&lt;long long*&gt;(p); 行创建了一个用 p 的值初始化的临时指向 long-long 的指针,这意味着它指向与 p 相同的内存区域(根据上面链接中的案例 6,这实际上是未定义的行为) ,然后取消引用它并将值分配给x。因为long long 通常是 8 个字节长,而 p 只指向 6 个有效字节,这个取消引用又是未定义的行为,但是你得到 228509037105(二进制 0x3534333231),这意味着你的机器是小端的,额外的 2 个字节是也是0。

如果你想得到x == 12345,正确的做法是long long x = std::stoll(p)

您还误解了“但是,据我后来得知,可以使用 reinterpret_cast 从 char 数组中读取 8 个字节”这一事实。 您可以做的是将char* 值转换为long long 值,假设您的机器上的sizeof void* 不大于sizeof(long long)(参见上面链接中的案例2)。如果sizeof void* 等于 8,那么您正在“从 'char 数组'(实际上是从指针到字符)中读取 8 个字节: long long x = reinterpret_cast&lt;long long&gt;(p)。这为您提供了 p 最初包含的地址,作为 long long 值存储在变量 x 中。除了将其转换回char* 之外,您对这个值所做的任何事情都是未定义的行为。 例如,您可以使用printf(reinterpret_cast&lt;char*&gt;(x)),它将打印您的原始字符缓冲区“12345”。

【讨论】:

    【解决方案3】:

    对于1,2,3,4 and 5 的ascii 值,底层字节是0x31, 0x32, 0x33, 0x34 and 0x35。把你收到的值转换成十六进制,你就会明白我在说什么了。

    reinterpret_cast 通常用于在指针类型之间转换或转换为另一种整数类型。例如,您可以将指针转换为数字,然后使用 sprintf 使用整数格式说明符而不是指针说明符来输出值

    【讨论】:

    • 您将使用从char *void * 的隐式转换,而static_cast 则用于另一种方式。根据我的经验,我将reinterpret_cast 用于SetWindowLongPtr 之类的东西,您可以将指针传递给采用整数类型的东西。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多