C++ C++;:如何将int转换为无符号long而不更改任何位?
C++:如何将int转换为无符号long而不更改任何位? 我想将值打包并解压缩到内存中。字大小为64位 此代码段说明了问题:C++ C++;:如何将int转换为无符号long而不更改任何位?,c++,casting,bit-manipulation,C++,Casting,Bit Manipulation,C++:如何将int转换为无符号long而不更改任何位? 我想将值打包并解压缩到内存中。字大小为64位 此代码段说明了问题: int v1 = -2; // 0xfe unsigned long v2=(unsigned long)v1; // 0xfffe, I want 0x00fe 简单的解决办法是: unsigned long v2=(unsigned int)v1; // 0x00fe 但是,此代码位于一个模板中,其中目标类型是一个参数,因此我不得不求助于此: uint64 tar
int v1 = -2; // 0xfe
unsigned long v2=(unsigned long)v1; // 0xfffe, I want 0x00fe
简单的解决办法是:
unsigned long v2=(unsigned int)v1; // 0x00fe
但是,此代码位于一个模板中,其中目标类型是一个参数,因此我不得不求助于此:
uint64 target = mem[index] & mask;
uint64 v;
if (value < 0) {
switch (bits) {
case 8:
v = (uint8)value;
break;
case 16:
v = (uint16)value;
break;
case 32:
v = (uint32)value;
break;
}
} else {
v = value;
}
v = v << lShift;
target |= v;
mem[index] = target;
uint64 target=mem[index]&mask;
uint64 v;
如果(值<0){
开关(位){
案例8:
v=(uint8)值;
打破
案例16:
v=(uint16)值;
打破
案例32:
v=(uint32)值;
打破
}
}否则{
v=值;
}
v=v如果你不介意输入,你会想到一个trait类:
template <typename IType> struct ToULong;
template <> struct ToULong<signed char>
{
static inline unsigned long int get(signed char c) { return (unsigned char)(c); }
};
template <> struct ToULong<signed short int>
{
static inline unsigned long int get(signed short int c) { return (unsigned short int)(c); }
};
/* ... signed int, signed long int, signed long long int ... */
第二次更新:如果你想更像C++,你可能应该说静态转换(x)
,而不是(T)(x)
。要转换而不改变位,取一个引用,然后用适当的类型取消引用:
int v1 = -2; // 0xfe
unsigned long v2=*(unsigned long *)&v1;
这假设大小相同。如果sizeof(int)!=sizeof(无符号长)。您可能需要unsigned int
编辑:意识到我回答了错误的问题
Boost type_traits(我相信它是make_unsigned)可以将int类型转换为unsigned版本(如果是有符号的),如果是unsigned则什么也不做 我相信您可以使用按位AND来获得所需的结果
unsigned long v2 = 0;
v2 = v2 | v1;
假设您有C++0x支持:
#include <type_traits>
v= static_cast<std::make_unsigned<decltype(value)>::type>(value);
#包括
v=静态压力(数值);
我假设您正在对值的类型进行参数化,否则这没有任何意义
编辑:使用static_cast
而不是C cast,使其更像C++-ish。我想这就是为什么我投了反对票。工会怎么样
union u1 {
short int si;
unsigned long int uli;
unsigned long int stub;
operator unsigned long int () {return uli;};
public:
u1(short int nsi) : stub(0) {si = nsi;}
};
利用“Kerrek SB”提出的想法,我想出了一个解决方案
template <typename Tint> uint64 ToMemdata(Tint value) {
return (uint64)value;};
template <> uint64 ToMemdata<int8>(int8 value) {
return (uint64)((uint8)value);};
template <> uint64 ToMemdata<int16>(int16 value) {
return (uint64)((uint16)value);};
template <> uint64 ToMemdata<int32>(int32 value) {
return (uint64)((uint32)value);};
template <> uint64 ToMemdata<int64>(int64 value) {
return (uint64)((uint64)value);};
template <typename Tint> void packedWrite(Tint value, int vectorIndex, uint64* pData) {
uint64 v = ToMemdata(value);
// This call eliminates a run time test for minus and a switch statement
// Instead the compiler does it based on the template specialization
uint64 aryix, itemofs;
vectorArrayIndex(vectorIndex, &aryix, &itemofs); // get the memory index and the byte offset
uint64 mask = vectorItemMask(itemofs); // get the mask for the particular byte
uint64 aryData = pData[aryix]; // get the word in memory
aryData &= mask; // mask it
uint64 lShift = (uint64)(itemofs * sizeof(Tint) * 8);
uint64 d = v << lShift; // shift the value into the byte position
aryData |= d; // put the value into memory
pData[aryix] = aryData;
}
模板uint64 TOMEDATA(色调值){
返回(uint64)值;};
模板uint64 TOMEDATA(int8值){
返回(uint64)((uint8)值);};
模板uint64 TOMEDATA(int16值){
返回(uint64)((uint16)值);};
模板uint64 TOMEDATA(int32值){
返回(uint64)((uint32)值);};
模板uint64 TOMEDATA(int64值){
返回(uint64)((uint64)值);};
模板void packedWrite(色调值、int向量索引、uint64*pData){
uint64 v=最大数据(值);
//此调用消除了减号和switch语句的运行时测试
//相反,编译器是基于模板专门化来完成的
uint64 aryix,itemofs;
vectorArrayIndex(vectorIndex、&aryix、&itemofs);//获取内存索引和字节偏移量
uint64 mask=vectoriemmask(itemofs);//获取特定字节的掩码
uint64 aryData=pData[aryix];//在内存中获取单词
aryData&=mask;//屏蔽它
uint64 lShift=(uint64)(itemofs*sizeof(色调)*8);
uint64 d=v不应该是按位还是按位?这总是会产生0。在执行操作之前,您仍然可以升级到一个普通类型。如果我没记错的话,将int*
转换为unsigned long*
和取消引用是未定义的行为。对于某些编译器,int和unsigned long的大小相同,这意味着e不是未定义的行为。这与联合非常相似。@Foo-只是它打破了严格的别名规则。通过指向另一个类型的指针访问一个类型是UB@Bo是*reinterpret_cast&v1 UB?@Foo-reinterpret_cast必须是实现定义的。否则我们不知道它是什么。标准将强制转换留给我们不同的指针类型直到实现。你有64位的字大小和16位的整数?这很特别。方法签名是什么?你只提供部分信息,因此只能期望部分好的解决方案。但我怀疑你可以使用boost::type_traits来帮助。你这样做的方式是不可移植的。如果你想保留位,请t当然,您需要使用类型双关:unsigned long v2=*(unsigned int*)&v1;
。否则,您将获得一个允许根据符号表示形式更改位的值转换。如果sizeof(int)!=sizeof(long int)那么无符号长字符的顶端可能是未定义的。@Rudy Velthuis请注意stub
成员。这看起来很有希望,因为编译器正在执行我的示例在运行时所做的工作。因此,我将添加“v=ToULong(value);”where“IntType”,而不是短语“if(value<0)”值变量的类型。您需要调用静态成员函数,ToULong::get(value)
——但我认为重载的自由函数也应该工作得很好,而且在概念上更简单一些。不过trait类为您提供了一些额外的类型安全性,因为自由函数也可以工作(毫无疑问)隐式可转换类型,这可能是意外的。
union u1 {
short int si;
unsigned long int uli;
unsigned long int stub;
operator unsigned long int () {return uli;};
public:
u1(short int nsi) : stub(0) {si = nsi;}
};
template <typename Tint> uint64 ToMemdata(Tint value) {
return (uint64)value;};
template <> uint64 ToMemdata<int8>(int8 value) {
return (uint64)((uint8)value);};
template <> uint64 ToMemdata<int16>(int16 value) {
return (uint64)((uint16)value);};
template <> uint64 ToMemdata<int32>(int32 value) {
return (uint64)((uint32)value);};
template <> uint64 ToMemdata<int64>(int64 value) {
return (uint64)((uint64)value);};
template <typename Tint> void packedWrite(Tint value, int vectorIndex, uint64* pData) {
uint64 v = ToMemdata(value);
// This call eliminates a run time test for minus and a switch statement
// Instead the compiler does it based on the template specialization
uint64 aryix, itemofs;
vectorArrayIndex(vectorIndex, &aryix, &itemofs); // get the memory index and the byte offset
uint64 mask = vectorItemMask(itemofs); // get the mask for the particular byte
uint64 aryData = pData[aryix]; // get the word in memory
aryData &= mask; // mask it
uint64 lShift = (uint64)(itemofs * sizeof(Tint) * 8);
uint64 d = v << lShift; // shift the value into the byte position
aryData |= d; // put the value into memory
pData[aryix] = aryData;
}