交换字节序


20

众所周知,(字节可寻址的)硬件存储器可分为两类:little-endianbig-endian。在小端存储中,字节在小(最低有效)端从0开始编号,而在大端存储则以相反的方式编号。

有趣的事实:这些用语基于乔纳森·斯威夫特Jonathan Swift)的《格列佛游记》(Gulliver's Travels),其中小人国国王下令其公民在小端(因此,小端)破蛋,而叛军则在大端破其卵。

交换的工作方式

假设我们12648430在big-endian机器中的内存中有一个无符号整数(32位),看起来可能如下:

  addr: 0  1  2  3
memory: 00 C0 FF EE

通过反向字节顺序,我们得到的十六进制整数0xEEFFC0004009738240十进制。

你的任务

编写一个程序/函数,该程序/函数接收十进制的无符号32位整数,并在如上所述交换字节序时输出结果整数。

规则

  • 输入将始终在范围04294967295
  • 可以将输出打印到STDOUT(跟踪换行符/空格很好)或返回
  • 输入和输出均为十进制
  • 无效输入的行为未定义

测试用例

0 -> 0
1 -> 16777216
42 -> 704643072
128 -> 2147483648
12648430 -> 4009738240
16885952 -> 3232235777
704643072 -> 42
3735928559 -> 4022250974
4009738240 -> 12648430
4026531839 -> 4294967279
4294967295 -> 4294967295

对于函数答案,“输入和输出以十进制表示”是否意味着需要一个数字字符字符串或一个数字值数组?还是函数答案可以使用其语言的自然整数值表示形式,而在大多数情况下,它与“十进制”绝对无关?
aschepler,2017年

1
@aschepler语言的整数值,例如。42以十进制表示,但从技术上讲,它以C语言表示为二进制。您当然可以输入0x2a,我想防止的是将输入作为字符串"2a"之类的。
ბიმო

相关(因为这个挑战只是确保首先填充到32位)
FlipTack

Answers:


25

x86_32机器语言,3个字节

endian_swap:        # to be called with PASCAL REGISTER calling convention
0f c8    bswap eax
c3       ret

这有点作弊。Pascal寄存器调用约定(请参阅Wikipedia)有点类似于__fastcall,不同之处在于它传递eax中的第一个参数,并且eax还包含返回值。这也是被调用方清理,但是由于我们除了返回指针外不将栈用于其他任何事情,因此我们无需执行任何操作。这使我们避免了mov或xchg,而直接使用bswap。


可能需要注意的是,bswap要求80486或更高:)
ceilingcat '17

@ceilingcat非常正确,尽管我确信由于编译器或工具链的限制,这里的许多其他解决方案都是隐含的!
多项式

10

x86_64机器语言Linux,5个 4字节

0:       0f cf                   bswap  %edi
2:       97                      xchg   %eax,%edi
3:       c3                      retq 

感谢@peter ferrie -1。

在线尝试!


那不是十进制的返回值。我认为这不重要。此外,您可以将xchg edi,eax保留4个字节。
彼得·费里

@peterferrie哇,我只是在浏览您的网站,以了解有关PE标头的信息!
ceilingcat '17


6

Japt10 14字节

sG ùT8 ò w ¬nG

试试吧


说明

将输入整数转换为以16为基数的字符串(sG),用于0将起始字符填充为长度8(ùT8),分割为2个字符串的数组(ò),反向(w),重新加入字符串(¬),然后转换回基数- 10(nG)。


您知道,方便的功能是拥有更多类似y的功能,当给一个功能一个功能时,应用其正常转换,运行该功能,然后反转转换。在这种情况下,我认为这可以将其缩短sG_ò w ¬为8个字节。或者,如果ò这样做的话,甚至可能sG_ò2_w是7 ...
ETHproductions

@ETHproductions我支持它;在欠&.单位J副词做到这一点,它是在打高尔夫球,有时真的很有帮助。但是,所有反转的编码可能都是乏味的。
科尔于2008年

@ETHproductions:“重载”越多越好:)我在拔品脱的同时写了这篇文章,原本有sG_òw...,对于我的一生,无法弄清楚为什么它不起作用!我终于意识到自己的错误!
毛茸茸的

输入少于2 << 24似乎不起作用...
Neil

谢谢,@ Neil; 稍后将解决该问题。看起来要花我4个字节。
毛茸茸的



5

APL + WIN 14个字节

256⊥⌽(4⍴256)⊤⎕

说明

⎕ prompt for screen input
(4⍴256)⊤ 4 byte representation in base 256
⌽ reverse bytes
256⊥ bytes from base 256 to integer

1
256⊥⌽⎕⊤⍨4⍴256为-1字节的工作吗?
暴民埃里克(Erik the Outgolfer)

⍨运算符在APL + WIN中不可用,因此答案是否定的,但对于Dyalog APL来说可能是肯定的
Graham

5

C#70 68字节

这可能不是最佳的。

68:

Func<uint,uint>f=n=>((n=n>>16|n<<16)&0xFF00FF00)>>8|(n&0xFF00FF)<<8;

70:

uint e(uint n){n=n>>16|n<<16;return(n&0xFF00FF00)>>8|(n&0xFF00FF)<<8;}

在线尝试!


您可以将赋值移动到return表达式中,然后使用表达式主体成员语法:uint e(uint n)=>((n=n>>16|n<<16)&0xFF00FF00)>>8|(n&0xFF00FF)<<8;64个字节。
hvd

@hvd对我而言,这并不是有效的表达式形式语法。但是,我能够使用shift重排技巧来减少2个字节。
多项式

我将评论中的内容复制并粘贴到您的TIO链接中,以确保没有错别字或类似内容,并且完全符合我的评论中的方式,它可以正常工作:TIO链接
hvd

我注意到0xFF00FF00是0xFF00FF的补码,想知道您是否可以利用它?但是将其声明为变量会占用太多字符
PrincePolka

哦! 好确实检查常量:你可以用0xFF00FF通过两次>>荷兰国际集团之前,&荷兰国际集团,然后你就可以缩短0xFF00FF~0u/257uint e(uint n)=>((n=n>>16|n<<16)>>8&~0u/257)|(n&~0u/257)<<8;对于60 TIO链接
HVD


4

05AB1E12 10字节

3F₁‰R`})₁β

在线尝试!说明:

  ₁         Integer constant 256
   ‰        [Div, Mod]
    R       Reverse
     `      Flatten to stack
3F    }     Repeat 3 times
       )    Collect results
        ₁β  Convert from base 256

1
这似乎不是一个有效的解决方案。在“填充”你做的其实就是重复字节的列表长度为4
埃里克Outgolfer

@EriktheOutgolfer Bah,我希望文档实际上会说……
Neil

3

JavaScript(ES6),45 43字节

f=(n,p=0,t=4)=>t?f(n>>>8,p*256+n%256,t-1):p

1
t=0保存2个字节开始:f=(n,p=t=0)=>t++<4?f(n>>>8,p*256+n%256):p
Arnauld


3

MATL12个 10字节

7Y%1Z%P7Z%

在线尝试!要么验证所有测试用例

说明

        % Implicitly input a number, read as a double
7Y%     % Cast to uint32
1Z%     % Convert to uint8 without changing underlying data. The result is 
        % an array of four uint8 numbers, each corresponding to a byte of
        % the original number's representation 
P       % Flip array
7Z%     % Convert back to uint32 without changing underlying data. The array
        % of four uint8 numbers is interpreted as one uint32 number.
        % Implicitly display

2

JavaScript(ES6),51 45字节

在@Neil的帮助下保存了6个字节

n=>(n>>>24|n>>8&65280|(n&65280)<<8|n<<24)>>>0

测试用例


很好,最好的递归方法是f=(n,p=0,t=4)=>t?f(n/256|0,p*256+n%256,t-1):p
ETHproductions

@ETHproductions ...那短吗?
暴民埃里克(Erik the Outgolfer)

1
@ETHproductions绝对短。您应该发布它。
Arnauld

46个字节:n=>(n>>>24|n>>8&65280|n<<8&16711680|n<<24)>>>0
Neil

1
@hvd不用担心。您可以将其添加为替代版本,也可以完全替换现有版本。由你决定!
Arnauld

2

J,16个字节

|.&.((4#256)#:])

在线尝试!

致力于缩短右侧表达。我认为我可以通过使用Beta J版本来节省一些字节。我发誓在这里看到您可以在新的Beta版本中以名词结束火车...

说明

|.&.((4#256)#:])
    ((4#256)#:])  Convert to 4 two-byte blocks
            #:      Debase to
      4#256         4 digits base 256
  &.              Apply right function, left function, then inverse of right
|.                Reverse digits

以256为基数转换为4位数字,反转数字,然后转换回十进制。基本上,执行OP中提供的算法。这也许是有一次,J的混合基数转换要求您指定数字的数量是有帮助的,尽管如果我可以用名词结尾的话((#:~4#256)代替),它将减少2个字节。


2

Excel VBA,103 92字节

匿名VBE立即窗口函数,该函数将范围的输入[A1]转换为十六进制,反转字节,然后输出到VBE立即窗口

h=[Right(Rept(0,8)&Dec2Hex(A1),8)]:For i=0To 3:s=s+Mid(h,7-2*i,2):Next:[B1]=s:?[Hex2Dec(B1)]

我可以在某个地方测试吗?您能添加一个在线口译员吗?
ბიმო

2
@BruceForte否,很遗憾,没有任何VBA变体的在线解释器,但是,如果您的计算机上有Excel副本,则可以通过按Alt + F11来访问VBE,然后通过按Ctrl来访问即时窗口+G。对于此匿名函数,您将输入粘贴到单元格A1中,并将上面的代码粘贴到立即窗口中,然后按Enter键
Taylor Scott

哦-有时VBA有点时髦(Mac版本绝对比Windows版本差),因此,除非另有说明,否则VBA解决方案假定默认的32位Windows版本
Taylor Scott

2

PPC汇编(32位),8字节

endian_swap:    # WORD endian_swap(WORD)
7c 60 1c 2c     LWBRX 3,0,3
4e 80 00 20     BLR

工作原理:

  • PPC调用约定将第一个32位word参数放入SP + 24,并将其影子写入GPR3。
  • LWBRX将加载GPR3(第三个操作数)并将其零扩展(第二个操作数)到EA,然后以相反的顺序读取4个字节并将其存储到GPR3(第一个操作数)中。
  • GPR3保存返回值。
  • BLR从函数返回(分支到LR寄存器中的地址)

不幸的是,我找不到任何在线PPC组装仿真器来演示。抱歉!


2

Befunge,62 61或49字节

0&0v!p22:/3g22/*:*82\+%*:*82+<
@.$_:28*:*%00p\28*:**00g28*:*^

在线尝试!

这是在参考解释器上使用标准Befunge,因此我们需要考虑以下事实:存储单元为8位带符号,并针对可能的带符号溢出进行校正。

在使用无符号存储单元(例如PyFunge)或范围大于8位(例如FBBI)的实现中,我们无需进行这些检查就可以节省12个字节。

0&0v!p22:/3g22/*:*82\+g<
@.$_:28*:*%00p\28*:**00^

在线尝试FBBI!
在线尝试PyFunge!

尽管注意PyFunge有一个处理整数输入的错误,所以在TIO上进行测试时,您需要在输入字段中的数字后加上空格或换行符。


2

八度,10字节

@swapbytes

在线尝试!

这可能是八度首次获得与高尔夫衍生品MATL完全相同的分数。当然,在这种情况下,具有内置功能而不是MATL的Octave使它变得更加容易。

定义一个内置的句柄,该句柄swapbytes采用任何数据类型,交换字节序并输出结果。在这种情况下,输入为32位无符号整数。



2

R,86字节

我以为R中已经有一个(或两个)这个问题的答案,但我一定是误会了,否则他们会遇到与R不做带符号整数相同的问题。该问题排除了所有可能有帮助的内建函数。我尝试了256基本转换,但是最终转换时间太长了,但是我认为还有比我更聪明的人可以这样做。然后,我得出以下结论:在递归函数中以2为基的转换交换了顺序。

f=function(x,y=0,i=31)'if'(i+1,f(x-(2^i*z),y+(2^((3-i%/%8)*8+i%%8)*(z=2^i<=x)),i-1),y)

在线尝试!

f=function(x,y=0,i=31)       # set up the function and initial values
  'if'(i+1,                  # test for i >= 0
    f(                       # recursively call the function
      x-(2^i*z),             # remove 2^i from x when 2^i <= x
      y+(2^                  # add to y 2 to the power of
        ((3-i%/%8)*8+i%%8)   # calc to swap the order of the bytes
        *(z=2^i<=x)),        # when 2^i <= x
      i-1),                  # decrement i
   y)                        # return y

您对 256基短一点是正确的
朱塞佩

@Giuseppe,您要戴上帽子吗
MickyT

2

R,41个字节

function(n)n%/%256^(0:3)%%256%*%256^(3:0)

在线尝试!

验证所有测试用例!

使用此处建议的以256为基的转换。R没有32位无符号整数,也没有64位整数。这阻止了我们使用按位运算,但是由于R的按位运算符非常冗长,因此这种方法(可能还有MickyT的方法)可能仍然更短。

利用本技巧的数字4 ,考虑到我们永远不会得到比数字大的数字256^4

n%/%256^(0:3)%%256提取字节,%*%在这种情况下,矩阵乘积是点积,并256^(3:0)影响字节的相反顺序。%*%将返回一个1x1,matrix其中包含字节序反转的值。


1

CP-1610组件,6个DECLE = 8字节

该代码旨在在Intellivision上运行。

CP-1610操作码使用10位值(称为“ DECLE”)进行编码。该函数的长度为6 DECLE,起始于$ 480C,结束于$ 4811。

CP-1610具有16位寄存器,因此我们使用其中两个(R0和R1)来存储32位值。

                               ROMW  10           ; use 10-bit ROM

                               ORG   $4800        ; start program at address $4800

                               ;; example call
4800  0001                     SDBD               ; load 0xDEAD into R0
4801  02B8 00AD 00DE           MVII  #$DEAD, R0
4804  0001                     SDBD               ; load 0xBEEF into R1
4805  02B9 00EF 00BE           MVII  #$BEEF, R1

4808  0004 0148 000C           CALL  swap32       ; call our function

480B  0017                     DECR  PC           ; loop forever

                               ;; swap32 function
                       swap32  PROC

480C  0040                     SWAP  R0           ; 16-bit SWAP of R0
480D  0041                     SWAP  R1           ; 16-bit SWAP of R1

480E  01C1                     XORR  R0, R1       ; exchange R0 and R1
480F  01C8                     XORR  R1, R0       ; using 3 consecutive eXclusive OR
4810  01C1                     XORR  R0, R1

4811  00AF                     JR    R5           ; return

                               ENDP

执行转储

 R0   R1   R2   R3   R4   R5   R6   R7    CPU flags  instruction
 ------------------------------------------------------------------
 0000 4800 0000 0000 01FE 1041 02F1 4800  ------iq   SDBD
 0000 4800 0000 0000 01FE 1041 02F1 4801  -----D-q   MVII #$DEAD,R0
 DEAD 4800 0000 0000 01FE 1041 02F1 4804  ------iq   SDBD
 DEAD 4800 0000 0000 01FE 1041 02F1 4805  -----D-q   MVII #$BEEF,R1
[DEAD BEEF]0000 0000 01FE 1041 02F1 4808  ------iq   JSR  R5,$480C

 DEAD BEEF 0000 0000 01FE 480B 02F1 480C  ------iq   SWAP R0
 ADDE BEEF 0000 0000 01FE 480B 02F1 480D  S------q   SWAP R1
 ADDE EFBE 0000 0000 01FE 480B 02F1 480E  S------q   XORR R0,R1
 ADDE 4260 0000 0000 01FE 480B 02F1 480F  ------iq   XORR R1,R0
 EFBE 4260 0000 0000 01FE 480B 02F1 4810  S-----iq   XORR R0,R1
[EFBE ADDE]0000 0000 01FE 480B 02F1 4811  S-----iq   MOVR R5,R7

 EFBE ADDE 0000 0000 01FE 480B 02F1 480B  ------iq   DECR R7

为什么是这7.5个字节?我认为应该是8个字节。
暴民埃里克(Erik the Outgolfer)'17年

@EriktheOutgolfer足够公平。相应地更新。
Arnauld

@EriktheOutgolfer因为60位等于7.5个字节?
杰普·斯蒂格·尼尔森

@JeppeStigNielsen是的,但是文件的长度永远不能为7.5字节,它将被预先或后缀0。
暴民埃里克(Erik the Outgolfer)'17年

@EriktheOutgolfer从技术上讲,它实际上可以存储在10位ROM中。是规格表示例。(今天,我们为Intellivision自制游戏使用16位ROM,但在过去,存储芯片非常昂贵,以至于使用10位确实可以省钱。)
Arnauld

1

C#(.NET Core),72 + 31 = 103字节

m=>BitConverter.ToUInt32(BitConverter.GetBytes(m).Reverse().ToArray(),0)

在线尝试!

+31 using System;using System.Linq;

我希望使用Array.Reverse内联,但事实并非如此(请参见下面的替代方法)。

C#(.NET Core),87 + 13 = 100字节

m=>{var a=BitConverter.GetBytes(m);Array.Reverse(a);return BitConverter.ToUInt32(a,0);}

在线尝试!

+13 using System;

@JeppeStigNielsen的解决方案;消除所有内联保存3个字节的限制。


因为可以保存using System.Linq;,所以使用起来仍然更便宜x=>{var a=BitConverter.GetBytes(x);Array.Reverse(a);return BitConverter.ToUInt32(a,0);}
杰普·斯蒂格·尼尔森

1

REXX,42字节

say c2d(left(reverse(d2c(arg(1))),4,'0'x))

在线尝试!

取消高尔夫:

n=arg(1) -- take n as argument
n=d2c(n) -- convert from decimal to character (bytes)
n=reverse(n) -- reverse characters
n=left(n,4,'0'x) -- extend to four bytes, padding with zeros
n=c2d(n) -- convert from bytes to decimal again
say n -- output result


1

ARM机器语言Linux,8个字节

0:       e6bf0f30       rev     r0, r0
4:       e12fff1e       bx      lr

要自己尝试,请在运行GNUroot的Raspberry Pi或Android设备上编译并运行以下命令

#include<stdio.h>
#define f(x) ((unsigned int(*)(unsigned int))"0\xf\xbf\xe6\x1e\xff/\xe1")(x)
int main(){
  printf( "%u %u\n", 0, f(0) );
  printf( "%u %u\n", 1, f(1) );
  printf( "%u %u\n", 42, f(42) );
  printf( "%u %u\n", 128, f(128) );
  printf( "%u %u\n", 16885952, f(16885952) );
  printf( "%u %u\n", 704643072, f(704643072) );
  printf( "%u %u\n", 3735928559U, f(3735928559U) );
  printf( "%u %u\n", 4009738240U, f(4009738240U) );
  printf( "%u %u\n", 4026531839U, f(4026531839U) );
  printf( "%u %u\n", 4294967295U, f(4294967295U) );
}



1

K4字节

解:

0b/:,/8#|12 8#0b\:

例子:

q)\
  0b/:,/8#|12 8#0b\:0
0
  0b/:,/8#|12 8#0b\:1
16777216
  0b/:,/8#|12 8#0b\:42
704643072
  0b/:,/8#|12 8#0b\:4294967295
4294967295
  0b/:,/8#|12 8#0b\:4026531839
4294967279

说明:

没有无符号的整数,因此需要输入很长的时间。

转换为布尔数组(64位),整形,反转,取前8个字节,然后转换回long。

0b/:,/8#|12 8#0b\: / the solution
              0b\: / convert to bits
         12 8#     / reshape into 12x8 grid (wraps)
        |          / reverse
      8#           / take first 8
    ,/             / flatten
0b/:               / convert to long

奖金:

19字节的版本确定您可以在线试玩!

2/,/8#|12 8#(64#2)\
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.