C 翻转字节,做算术,然后再次翻转它们

C 翻转字节,做算术,然后再次翻转它们,c,endianness,C,Endianness,我有一个与编程/数学相关的问题,关于在big-endian和little-endian之间转换以及做算术 假设在小端模式下有两个整数: int a = 5; int b = 6; //a+b = 11 让我们翻转字节并再次添加它们: int a = 1280; int b = 1536; //a+b = 2816 现在,如果我们翻转2816的字节顺序,我们得到11。所以本质上我们可以在小端点和大端点之间进行算术计算,一旦转换,它们代表相同的数字 在计算机科学界,这背后有没有一个理论/名称?这

我有一个与编程/数学相关的问题,关于在big-endian和little-endian之间转换以及做算术

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

int a = 5;
int b = 6;
//a+b = 11
让我们翻转字节并再次添加它们:

int a = 1280;
int b = 1536;
//a+b = 2816
现在,如果我们翻转
2816
的字节顺序,我们得到
11
。所以本质上我们可以在小端点和大端点之间进行算术计算,一旦转换,它们代表相同的数字


在计算机科学界,这背后有没有一个理论/名称?

这似乎只起作用,因为你碰巧选择了足够小的数字,使它们以及它们的总和都能放入一个字节。只要数字中的所有内容都保持在各自的字节内,就可以随意地对字节进行洗牌和去洗牌,这不会有什么区别。如果您选择较大的数字,例如1234和4321,您将注意到它不再起作用。事实上,您很可能会调用未定义的行为,因为您的
int
将溢出


除此之外,您几乎肯定会想阅读以下内容:

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

让我们看一个十六进制的例子,假设endianness意味着每个4位半字节都被交换:

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

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

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

首先,应该注意,你认为C中的
int
有16位的假设是错误的。在大多数现代系统中,
int
是一种32位类型,因此如果我们反转(而不是翻转,这通常意味着取补码)5的字节,我们将得到83886080(0x05000000),而不是1280(0x0500)

还要注意的是,您应该使用十六进制来编写,以便于理解,因为计算机不是以十进制工作的:

int16_t a = 0x0005;
int16_t b = 0x0006;
// a+b = 0x000B

int16_t a = 0x0500; // 1280
int16_t b = 0x0600; // 1536
//a+b = 0x0B00
好了,正如其他人所说,
ntohl(htonl(5)+htonl(6))
恰好与5+6相同,只是因为你有一些小数字,它们的倒数之和不会溢出。选择较大的数字,您将立即看到差异


但是,对于值存储在两个较小部分(如本例)的系统,该属性确实适用

在一的补码中,一个人通过将进位传回进位来进行算术运算。如果一个人因为“循环进位”而只有一个内部“进位中断”(即存储的值被分为两个独立的块),那么他的补码运算就变得独立了

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

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

+zz您刚好选择了两个不会溢出的数字。这就像说乘法和加法是一样的,因为
2+2==2*2