如何将有符号整数转换为大端序?

huangapple go评论61阅读模式
英文:

How to convert a signed integer to big-endian?

问题

让我们假设我的系统上有一个带符号整数,并且它以小端存储。

int32_t x = -456;

我该如何编写一个函数,将其转换为大端,以便可以将其存储在具有与我的系统不同符号的文件中?

这是我的尝试:

int32_t big_endian(int32_t x) {
    int sign = (x < 0) ? -1 : 1;
    uint32_t y = (uint32_t)x;
    
    // 翻转 y 的位
    
    return (int32_t)y * sign;
}

我担心最左边的比特位会影响符号,因为我觉得转换为无符号,然后翻转,会把符号位放到错误的字节中。

英文:

Let's assume I have a signed integer on my system and it is stored as little endian.

int32_t x = -456;

How do I make a function that converts this to big endian so I can store it in a file with different signedness from my system?

This is my attempt:

int32_t big_endian(int32_t x) {
    int sign = (x &lt; 0) ? -1 : 1;
    uint32_t y = (uint32_t)x;
    
    // flip bits of y
    
    return (int32_t)y * sign;
}

I am concerned about that leftmost bit that determines the signedness, because I feel that converting to unsigned, and then flipping, will return the signedness bit to the wrong byte.

答案1

得分: 2

计算表示 int32_t 的字节可能因为 C 标准未完全定义带有负值的位移而略显麻烦。然而,由于精确宽度的有符号整数类型被定义为使用二进制补码,它们的表示与通过将有符号类型转换为无符号类型获得的相应无符号整数类型的表示相同。所以我们可以转换为 uint32_t 并进行位移以获得所需的字节,如下面的代码所示。

英文:

Calculating the bytes that represent an int32_t can be a slight nuisance due to the C standard not fully defining shifts with negative values. However, since the exact-width signed integer types are defined to use two’s complement, their representations are the same as for the corresponding unsigned integer type obtained by converting the signed type to the unsigned type. So we can convert to uint32_t and shift to obtain the desired bytes, as the following code demonstrates.

#include &lt;stdlib.h&gt;
#include &lt;limits.h&gt;


/*	Convert a big-endian object to a little-endian object or vice-versa,
   	in place.
*/
void ReverseEndian(void *p, size_t n)
{
	//	Convert to &quot;unsigned char *&quot; for convenience.
	unsigned char *pu = p;

	/*	Swap bytes at the front of the object with reflected bytes from the
		back.
	 */
	for (size_t i = 0; i &lt; n/2; ++i)
	{
		unsigned char t = pu[i];
		pu[i] = pu[n-1-i];
		pu[n-i-1] = t;
	}
}


//	Store an int32_t as big-endian.
void StoreBigEndian(void *p, int32_t x)
{
	//	Convert to &quot;unsigned char *&quot; for convenience.
	unsigned char *pu = p;

	/*	Convert to uint32_t.  Since int32_t is defined to use two’s complement,
		uint32_t is represented with the sign bytes, and it avoids the sign
		issues.
	*/
	uint32_t u = x;

	/*	Shift each byte, starting with the least significant, to move it to
		the low byte, then store those bytes in big-endian order, starting
		with the highest addressed.
	*/
	for (size_t i = 0; i &lt; sizeof u; ++i)
		pu[sizeof u - 1 - i] = u &gt;&gt; i*CHAR_BIT;
}


//	Store an int32_t as little-endian.
void StoreLittleEndian(void *p, int32_t x)
{
	//	Convert to &quot;unsigned char *&quot; for convenience.
	unsigned char *pu = p;

	/*	Convert to uint32_t.  Since int32_t is defined to use two’s complement,
		uint32_t is represented with the sign bytes, and it avoids the sign
		issues.
	*/
	uint32_t u = x;

	/*	Shift each byte, starting with the least significant, to move it to
		the low byte, then store those bytes in big-endian order, starting
		with the lowest addressed.
	*/
	for (size_t i = 0; i &lt; sizeof u; ++i)
		pu[i] = u &gt;&gt; i*CHAR_BIT;
}


#include &lt;stdio.h&gt;


//	Print n bytes starting at address p.
static void PrintBytes(const void *p, size_t n)
{
	//	Convert to &quot;unsigned char *&quot; for convenience.
	const unsigned char *pu = p;

	printf(&quot;Hexadecimal&quot;);
	for (size_t i = 0; i &lt; n; ++i)
		printf(&quot; %0*x&quot;, (CHAR_BIT+3)/4, pu[i]);
}


#include &lt;string.h&gt;


int main(void)
{
	int32_t i = 0x12345678;

	//	Buffers for big-endian and little-endian representations.
	unsigned char BE[sizeof i];
	unsigned char LE[sizeof i];

	//	Store the value as big endian and display it.
	StoreBigEndian(BE, i);
	printf(&quot;Big Endian:  &quot;); PrintBytes(BE, sizeof BE); printf(&quot;.\n&quot;);

	//	Store the value as little endian and display it.
	StoreLittleEndian(LE, i);
	printf(&quot;Little Endian:  &quot;); PrintBytes(LE, sizeof LE); printf(&quot;.\n&quot;);

	//	Copy the bytes into new int32_t objects to reinterpret them.
	int32_t ibe, ile;
	memcpy(&amp;ibe, BE, sizeof ibe);
	memcpy(&amp;ile, LE, sizeof ile);

	if (ibe == i)
		printf(&quot;This system appears to be big endian.\n&quot;);
	else if (ile == i)
		printf(&quot;This system appears to be little endian.\n&quot;);
	else
		printf(&quot;This system appears to be neither big endian nor little endian.\n&quot;);

	//	Reverse the endianness and test for problems.
	ReverseEndian(BE, sizeof BE);

	if (memcmp(BE, LE, sizeof BE))
	{
		fprintf(stderr, &quot;Error, big-endian bytes are inconsistent with little-endian bytes.\n&quot;);
		exit(EXIT_FAILURE);
	}
}

答案2

得分: 1

不要重新发明轮子,当你需要将主机数据转换为大端格式时。对于32位整数值,只需使用htonl()

概要

#include <arpa/inet.h>

uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

描述

这些函数将在网络字节顺序主机字节顺序之间转换16位和32位的数量。

在某些实现中,这些函数被定义为宏。

uint32_tuint16_t 类型在<inttypes.h>中定义。

返回值

htonl()htons() 函数将返回从主机到网络字节顺序转换的参数值。

也可在Windows上使用

英文:

Don't reinvent the wheel when you need to convert your host's data to big-endian format. For 32-bit integer values, just use htonl():

> SYNOPSIS
>
> #include <arpa/inet.h>
>
> uint32_t htonl(uint32_t hostlong);
> uint16_t htons(uint16_t hostshort);
> uint32_t ntohl(uint32_t netlong);
> uint16_t ntohs(uint16_t netshort);
>
> DESCRIPTION
>
> These functions shall convert 16-bit and 32-bit quantities between network byte order and host byte order.
>
> On some implementations, these functions are defined as macros.
>
> The uint32_t and uint16_t types are defined in &lt;inttypes.h&gt;.
>
> RETURN VALUE
>
> The htonl() and htons() functions shall return the argument value converted from host to network byte order.

It's also available on Windows.

huangapple
  • 本文由 发表于 2023年4月16日 23:50:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/76028774.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定