翻转字节,进行算术,然后再次将它们翻转回

时间:2019-04-30 00:46:01

标签: c endianness

我有一个与编程/数学相关的问题,涉及在大字节序和小字节序之间进行转换并进行算术运算。

假设我们在小端模式下有两个整数:

int a = 5;
int b = 6;
//a+b = 11

让我们翻转字节并再次添加它们:

int a = 1280;
int b = 1536;
//a+b = 2816

现在,如果我们翻转2816的字节顺序,我们将得到11。那么从本质上讲,我们可以在小端和大端之间进行算术计算,一旦转换,它们就代表相同的数字?

在计算机科学界,它背后是否有理论/名称?

3 个答案:

答案 0 :(得分:1)

如果加法涉及进位,则无效,因为进位是从右向左传播的。交换数字并不意味着携带切换方向,因此溢出到下一个字节的任何字节都会不同。

让我们看一个十六进制的示例,假装字节序意味着每个4位半字节被交换:

int a = 0x68;
int b = 0x0B;
//a+b:  0x73

int a = 0x86;
int b = 0xB0;
//a+b: 0x136

8 16 + B 16 是13 16 。 1被携带并加到第一个和中的6上。但是在第二个和中,它没有被右移并加到6,它被左移并溢出到第三个十六进制数字。

答案 1 :(得分:0)

这似乎是可行的,因为您碰巧选择了足够小的数字,以便它们及其和适合一个字节。只要数字中发生的所有事情都停留在其各自的字节之内,您显然可以随意对字节进行洗牌和洗牌,这不会有任何不同。如果您选择较大的数字,例如1234和4321,您会注意到它不再起作用。实际上,您极有可能最终会调用未定义的行为,因为您的int将溢出…

除此之外,您几乎肯定会想要阅读以下内容:ip-masq-agent

答案 2 :(得分:0)

首先,应注意,您对C中的int具有16位的假设是错误的。在大多数现代系统中,int是32位类型,因此如果我们反转(而不是翻转,这是补码)5个字节,我们将得到83886080,而不是1280

现在就如其他人所说,ntohl(htonl(5) + htonl(6)) 可能与5 + 6相同,只是因为您的数字很小,他们的反向求和不会溢出。选择较大的数字,您会立即看到差异


对于在这种情况下将值存储在2个较小的部分中的系统,该属性保留在ones' complement

在一个补语中,一个人通过向进位进位传播进位来对end-around carry进行算术运算。如果一个补语中只有一个内部“进位”,则补语就成为 endian独立中断”(即,存储的值分为两个单独的块)

假设我们有xxyy和zztt,那么xxyy + zztt就是这样

            carry
        xx        yy
      + zz <───── tt
      ──────────────
  carry aa        bb
     │             ↑
     └─────────────┘

当我们反转这些块时,yyxx + ttzz的携带方式相同。因为xx,yy,zz,tt是任意长度的位块,所以它适用于PDP的混合字节序,或者当您将32位数字存储在两个16位部分中时,将64位数字存储在两个32位部分中...

例如:

  • 0x7896 + 0x6987 = 0xE21D
    • 0x9678 + 0x8769 = 0x11DE1→0x1DE1 + 1 = 0x1DE2
  • 0x2345 + 0x9ABC = 0xBE01
    • 0x4523 + 0xBC9A = 0x101BD→0x01BD + 1 = 0x01BE
  • 0xABCD + 0xBCDE = 0x168AB→0x68AB + 1 = 0x68AC
    • 0xCDAB + 0xDEBC = 0x1AC67→0xAC67 + 1 = 0xAC68

或者上面的John Kugelman的示例:0x68 + 0x0B = 0x73; 0x86 + 0xB0 = 0x136→0x36 + 1 = 0x37

末端进位进位是选择TCP校验和的补码的原因之一,因为您可以轻松地以较高的精度计算和。 16位CPU可以像通常一样以16位单元工作,但是32位和64位CPU可以并行添加32位和64位块,而不必担心SWAR技术无法使用SIMD时的进位。