正如其他人现在提到的那样,我不确定是否ptr[k] = ((val >> (k*len)) && 0xFF);
符合您的要求。&&
运算符是布尔运算符。如果(value >> (k*len))
是某个非零值,并且0xFF
是某个非零值,则存储到其中的值ptr[k]
将为一。这就是布尔运算符的工作方式。也许您打算使用&
而不是&&
.
此外,您选择了使用移位运算符,它适用于unsigned
类型,但对于有符号类型有多种不可移植的方面。xx = xx |(ptr[m]<<(m*8));
例如,可能会调用未定义的行为,因为它看起来可能导致有符号整数溢出。
在C 中,sizeof (char)
始终为1,因为运算符告诉您使用多少个 s 来表示一个类型。例如。告诉你用多少个 s 来表示s。就是这样的变化。因此,您的代码不应依赖于a 类型。sizeof
char
sizeof (int)
char
int
CHAR_BIT
sizeof
事实上,如果您希望您的代码是可移植的,那么您不应该期望能够在 中存储大于 32767 或小于 -32767 的值int
。这与大小无关,因为可能存在填充位。总结一下:sizeof
a 类型不一定反映它可以存储的值集!
为他们的应用程序选择变量的类型,可移植。如果您的应用程序不需要超出该范围的值,那么int
就可以了。否则,您可能需要考虑使用 a long int
,它可以便携地存储(包括)-2147483647 和 2147483647 之间的值。如果您需要超出此范围的值,请使用 a long long int
,这将为您提供至少包含 -9223372036854775807 和 9223372036854775807 之间的值的保证范围。超出此范围的任何内容都可能需要一个多精度算术库,例如GMP。
当您不希望使用负值时,您应该使用unsigned
类型。
考虑到整数类型的可移植选择,现在可以设计一种可移植的方式将这些整数写入文件并从文件中读取这些整数是有意义的。您需要将符号和绝对值提取到unsigned int
:
unsigned int sign = val < 0; /* conventionally 1 for negative, 0 for positive */
unsigned int abs_val = val;
if (val < 0) { abs_val = -abs_val; }
...然后构造一个 8 位块的数组abs_val
and sign
,合并在一起。我们已经决定使用可移植决策,我们int
只能存储 16 位,因为我们只在其中存储 -32767 和 32767 之间的值。因此,不需要循环或按位移位。我们可以使用乘法来移动我们的符号位,并使用除法/取模来减少我们的绝对值。考虑到符号通常与最高有效位一起出现,它位于数组的开头(大端)或结尾(小端)。
unsigned char big_endian[] = { sign * 0x80 + abs_val / 0x100,
abs_value % 0x100 };
unsigned char lil_endian[] = { abs_value % 0x100,
sign * 0x80 + abs_val / 0x100 };
为了反转这个过程,我们执行相反的操作(即用除法和模代替乘法,用乘法代替除法和加法,提取符号位并重新计算值):
unsigned int big_endian_sign = array[0] / 0x80;
int big_endian_val = big_endian_sign
? -((array[0] % 0x80) * 0x100 + array[1])
: ((array[0] % 0x80) * 0x100 + array[1]);
unsigned int lil_endian_sign = array[1] / 0x80;
int lil_endian_val = lil_endian_sign
? -((array[1] % 0x80) * 0x100 + array[0])
: ((array[1] % 0x80) * 0x100 + array[0]);
对于 ,代码变得更复杂一些long
,因此值得使用二元运算符。符号和绝对值的提取基本上保持不变,唯一的变化是变量的类型。我们仍然不需要循环,因为我们决定只关心可移植表示的值。这是我从 a 转换为 along val
的方法unsigned char[4]
:
unsigned long sign = val < 0; /* conventionally 1 for negative, 0 for positive */
unsigned long abs_val = val;
if (val < 0) { abs_val = -abs_val; }
unsigned char big_endian[] = { (sign << 7) | ((abs_val >> 24) & 0xFF),
(abs_val >> 16) & 0xFF,
(abs_val >> 8) & 0xFF,
abs_val & 0xFF };
unsigned char lil_endian[] = { abs_val & 0xFF,
(abs_val >> 8) & 0xFF,
(abs_val >> 16) & 0xFF,
(sign << 7) | ((abs_val >> 24) & 0xFF) };
...这就是我将如何转换回签名值:
unsigned int big_endian_sign = array[0] >> 7;
long big_endian_val = big_endian_sign
? -((array[0] & 0x7F) << 24) + (array[1] << 16) + (array[2] << 8) + array[3]
: ((array[0] & 0x7F) << 24) + (array[1] << 16) + (array[2] << 8) + array[3];
unsigned int lil_endian_sign = array[3] >> 7;
long lil_endian_val = lil_endian_sign
? -((array[3] & 0x7F) << 24) + (array[2] << 16) + (array[1] << 8) + array[0]
: ((array[3] & 0x7F) << 24) + (array[2] << 16) + (array[1] << 8) + array[0];
我会让你设计一个方案unsigned
和long long
类型......并打开地板征求意见: