我目前正在参与一个将C++移植到 C# 代码的项目,但有些片段并不容易将 1 移植到 1,如下所示:
#define CMND_MOVEL 10
#define CMND_EXTRASIDE 0x80
char CmndBuffer[32];
int *dst;
dst = (int*) &CmndBuffer[0];
*dst = 0;
*dst |= (CMND_MOVEL + (Flags << 8));
if (BoxSide) *dst |= CMND_EXTRASIDE;
dst++;
*dst = SequenceNr;
dst++;
*dst = 10 * LastDestination.x;
dst++;
*dst = 10 * LastDestination.y;
dst++;
*dst = 10 * LastDestination.z;
dst++;
*dst = Speed * 10;
dst++;
*dst = Accel * 10;
result = ERR_COMMSOCK;
if (UdpCmdSocket >= 0)
{
if (sendto(UdpCmdSocket, (const char*) CmndBuffer, 28, 0, (struct sockaddr*)&UdpCmdPeer, sizeof(UdpCmdPeer)) != SOCKET_ERROR)
{
// more logic here
}
}
有人可以详细解释我这里发生了什么吗?我非常了解指针和位移的工作原理,但我不能 100% 确定在字节级别上发生了什么。我看到的是它正在填充一个数据包以将其扔到 UDP 上。
但更重要的是:如何在 C# 中发送它?(我将使用 .NET 套接字类)
我知道这可以被认为是一个懒惰的问题,但我想也许 SO 可以帮助我解决这个问题。
谢谢
原始代码可能假设sizeof(int)
是 4,这是标准无法保证的。 无论如何,它使用第一个字节来保存CMND_MOVEL
和CMD_EXTRASIDE
位,其余 3 个字节来保存 Flags
的值。 布局是这样的:
-------------------------------------------------------------
| Flags<<8 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| CMD_MOVEL | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
| CMD_EXTRASIDE | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-------------------------------------------------------------
C/C++ 中的每个char
都是一个字节,对应于 C# 中的byte
类型。 作者想要发送比这更长的值,因此他们使用int*
一次写入 4 个字节。
这部分:
//CmndBuffer[0] to zero
*dst = 0;
实际上设置为 0 CmndBuffer[0]
到 CmdBuffer[3]
. 由于它们将dst
指针递增六倍,因此它们最终写入 CmdBuffer[27]
. 最后四个字节似乎留下了未初始化的值。
如果要逐字节写入,则需要使用位移和掩码。 像这样:
byte[] buffer = /*...*/;
int index = /*...*/;
int sequenceNr = /*...*/;
buffer[index] = (byte) (sequenceNr >> 24) & 0xFF;
buffer[++index] = (byte) (sequenceNr >> 16) & 0xFF;
buffer[++index] = (byte) (sequenceNr >> 8) & 0xFF;
buffer[++index] = (byte) sequenceNr & 0xFF;
我会尝试添加一些注释以澄清
//some constants for later use
#define CMND_MOVEL 10
#define CMND_EXTRASIDE 0x80
char CmndBuffer[32];
int *dst;
//Load the address of the first element of CmndBuffer into dst;
dst = (int*) &CmndBuffer[0];
//CmndBuffer[0] to zero
*dst = 0;
//this loads (CMND_MOVEL + (Flags << 8) into dst. Flags << 8 means a multiplication with 2^8
*dst |= (CMND_MOVEL + (Flags << 8));
if (BoxSide) *dst |= CMND_EXTRASIDE;
//go to the next array element. The same applies to the commands below
dst++;
//write the value into the current array element
*dst = SequenceNr;
dst++;
*dst = 10 * LastDestination.x;
dst++;
*dst = 10 * LastDestination.y;
dst++;
*dst = 10 * LastDestination.z;
dst++;
*dst = Speed * 10;
dst++;
*dst = Accel * 10;
result = ERR_COMMSOCK;
if (UdpCmdSocket >= 0)
{
if (sendto(UdpCmdSocket, (const char*) CmndBuffer, 28, 0, (struct sockaddr*)&UdpCmdPeer, sizeof(UdpCmdPeer)) != SOCKET_ERROR)
{
// more logic here
}
}
至于你问题的第二部分,看看这个
Lukas 已经涵盖了其中的大部分内容;但它实际上所做的是使用指针数学沿着数组移动。所以这个:
dst++;
*dst = 10 * LastDestination.x;
在 C# 中看起来像这样
var arrayIndex = 0;
CmndBuffer[arrayIndex++] = 10 * LastDestination.x;
CmndBuffer[arrayIndex++] = 10 * LastDestination.y;
等等。