首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将ulong转换为long

将ulong转换为long
EN

Stack Overflow用户
提问于 2017-04-20 18:12:23
回答 3查看 5.5K关注 0票数 2

我有一个数字存储为ulong。我希望存储在内存中的比特以2的补充方式进行解释。所以我希望第一个位是符号位等等,如果我想转换成一个长,那么这个数字被正确地解释为一个2的补码,我该怎么做呢?

我尝试创建指向同一缓冲区的不同数据类型的指针。然后,我将ulong存储到缓冲区中。然后我取消了一个长指针。但这却给了我一个不好的结果?

我做了:

代码语言:javascript
复制
#include <iostream>
using namespace std;

int main() {
    unsigned char converter_buffer[4];//  

    unsigned long       *pulong;
    long                *plong;


    pulong = (unsigned long*)&converter_buffer;
    plong  =  (long*)&converter_buffer;

    unsigned long ulong_num = 65535; // this has a 1 as the first bit

    *pulong = ulong_num;

    std:: cout << "the number as a long is" << *plong << std::endl;
    return 0;
}

出于某种原因,这给了我同样的正数。选演员有帮助吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-04-20 20:20:12

实际上,使用指针是一个很好的开端,但您必须先将unsigned long*转换为void*,然后才能将结果转换为long*并取消引用:

代码语言:javascript
复制
#include <iostream>
#include <climits>

int main() {
    unsigned long ulongValue = ULONG_MAX;
    long longValue = *((long*)((void*)&ulongValue));

    std::cout << "ulongValue: " << ulongValue << std::endl;
    std::cout << "longValue:  " << longValue << std::endl;

    return 0;
}

上述代码将产生以下结果:

代码语言:javascript
复制
ulongValue: 18446744073709551615
longValue:  -1

有了模板,您可以在代码中使其更易读:

代码语言:javascript
复制
#include <iostream>
#include <climits>

template<typename T, typename U>
T unsafe_cast(const U& from) {
    return *((T*)((void*)&from));
}

int main() {
    unsigned long ulongValue = ULONG_MAX;
    long longValue = unsafe_cast<long>(ulongValue);

    std::cout << "ulongValue: " << ulongValue << std::endl;
    std::cout << "longValue:  " << longValue << std::endl;

    return 0;
}

请记住,这个解决方案绝对是不安全的,因为您可以对void*进行任何转换。这种做法在C中很常见,但我不建议在C++中使用它。考虑以下情况:

代码语言:javascript
复制
#include <iostream>

template<typename T, typename U>
T unsafe_cast(const U& from) {
    return *((T*)((void*)&from));
}

int main() {
    std::cout << std::hex << std::showbase;

    float fValue = 3.14;
    int iValue = unsafe_cast<int>(fValue); // OK, they have same size.

    std::cout << "Hexadecimal representation of " << fValue
              << " is: " << iValue << std::endl;
    std::cout << "Converting back to float results: "
              << unsafe_cast<float>(iValue) << std::endl;

    double dValue = 3.1415926535;
    int lossyValue = unsafe_cast<int>(dValue); // Bad, they have different size.

    std::cout << "Lossy hexadecimal representation of " << dValue
              << " is: " << lossyValue << std::endl;
    std::cout << "Converting back to double results: "
              << unsafe_cast<double>(lossyValue) << std::endl;

    return 0;
}

上述代码对我的结果如下:

代码语言:javascript
复制
Hexadecimal representation of 3.14 is: 0x4048f5c3
Converting back to float results: 3.14
Lossy hexadecimal representation of 3.14159 is: 0x54411744
Converting back to double results: 6.98387e-315

对于最后一行,您可以得到任何信息,因为转换将从内存中读取垃圾。

编辑

正如lorro评论的那样,使用memcpy()更安全,可以防止溢出。因此,下面是另一个更安全的类型铸造版本:

代码语言:javascript
复制
template<typename T, typename U>
T safer_cast(const U& from) {
    T to;
    memcpy(&to, &from, (sizeof(T) > sizeof(U) ? sizeof(U) : sizeof(T)));
    return to;
}
票数 3
EN

Stack Overflow用户

发布于 2017-04-20 22:27:38

你可以这样做:

代码语言:javascript
复制
uint32_t u;
int32_t& s = (int32_t&) u;

然后,您可以将su与2的补码互换使用,例如:

代码语言:javascript
复制
s = -1;
std::cout << u << '\n';     // 4294967295

在你的问题中,你问了大约65535,但这是一个正数。你可以这样做:

代码语言:javascript
复制
uint16_t u;
int16_t& s = (int16_t&) u;

u = 65535;
std::cout << s << '\n';    // -1

注意,将65535 (一个正数)分配给int16_t将实现自定义的行为,它不一定会给-1带来好处。

原始代码的问题是不允许将char缓冲区别名为long。(并且您可能会溢出缓冲区)。但是,可以将整数类型别名为其对应的有符号/无符号类型。

票数 0
EN

Stack Overflow用户

发布于 2017-04-20 18:25:26

通常,当您有两个大小相同的算术类型,并且希望使用另一个类型重新解释其中一个的位表示时,您可以使用一个union来完成它。

代码语言:javascript
复制
#include <stdint.h>

union reinterpret_u64_d_union {
    uint64_t u64;
    double   d;
};

double
reinterpret_u64_as_double(uint64_t v)
{
    union reinterpret_u64_d_union u;
    u.u64 = v;
    return u.d;
}

但是,对于将无符号数字转换为相同大小的有符号类型(反之亦然)的特殊情况,只需使用传统的强制转换:

代码语言:javascript
复制
int64_t
reinterpret_u64_as_i64(uint64_t v)
{
    return (int64_t)v;
}

( [u]int64_t并不严格要求强制转换,但是如果没有显式编写强制转换,而且转换的类型很小,则可能会涉及“整数提升”,这通常是不可取的。)

您试图这样做的方式违反了指针混叠规则,并引发了未定义的行为。

在C++中,请注意,reinterpret_cast<> 不执行union所做的操作;当应用于算术类型时,它与static_cast<>相同。

在C++中,还请注意,上面提到的union的使用依赖于1999年C标准中的一条规则(带有更正),而这条规则还没有被正式纳入到C++标准中;但是,我熟悉的所有编译器都将按照您的预期执行。

最后,在C和C++中,longunsigned long保证至少能够分别表示2,147,483,647. 214,7483,647和0. 4,294,967,295。您的测试程序使用了65535,这保证了longunsigned long都是可表示的,所以不管您做什么,这个值都不会改变。嗯,除非你使用无效的指针混叠,编译器决定让恶魔飞出你的鼻子。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43526910

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档