在 ARM 上使用 Span<T> 会给出“System.DataMisalignedException:”

Using Span<T> on ARM gives "System.DataMisalignedException:"

提问人:Ingar Hjelle 提问时间:1/25/2023 最后编辑:Guru StronIngar Hjelle 更新时间:1/25/2023 访问量:152

问:

我正在尝试读取数据并使用 .NET 7 从 Modbus RTU 传感器转换数据。一切都在我的 Linux-x64 机器上工作,但当我尝试在 RevPi 核心 S linux-arm 上运行它时,情况就不一样了......

Modbus RTU 配置传感器说明

我正在使用 FluentModbus 版本 5.0.2:


fluentClient = new ModbusRtuClient()
{
    BaudRate = 9600,
    Parity = Parity.None,
    StopBits = StopBits.One
};
fluentClient.Connect("/dev/ttyUSB" + port, ModbusEndianness.LittleEndian);

Console.WriteLine("Reading Calibration");
var calibration = fluentClient.ReadHoldingRegisters(1, 8704, 4);

var hexCalibration = Convert.ToHexString(calibration);

foreach (var item in calibration)
{
    Console.Write(item);
}

foreach (var item in hexCalibration)
{
    Console.Write(item);
}
//The code below works perfect on my machine running Ubuntu 22.04(linux-x64) but does not work //on RevPi Core running Debian custom Buster image (Linux-arm).
var floatCalibration = fluentClient.ReadHoldingRegisters<float>(1, 8704, 4);
Console.WriteLine("calibration K: " + floatCalibration[0]);
Console.WriteLine("calibration B: " + floatCalibration[1]);

终端输出 我的电脑:

Reading Calibration
000631541535764
0000003F9A993940
calibration K: 0.5
calibration B: 2.9

终端输出 RevPi Core

Reading Calibration
000631541535764
0000003F9A993940
Unhandled exception. System.DataMisalignedException: A datatype misalignment was detected in a load or store instruction.
   at exsys.Program.Main(String[] args) in /home/user/FunctionTest/Program.cs:line 179
Aborted

这是第 179 行: Console.WriteLine("calibration K: " + floatCalibration[0]);

是不是不能使用.Net7 Span<float> 在 linux Arm 上?我尝试了不同的设置,但还没有运气。也许其他人遇到了这个问题?

尝试将 dotnet publish 发布到独立的 linux-x64,一切正常。我只有在编译到 linux-arm 并运行它时才会收到错误。 尝试了不同的转换设置,但没有运气。 我已经更新了 2022 年 11 月发布的 RevPi Core S 上的映像,但它没有帮助。 尝试首先在 .NET 6 上运行,现在在 .NET 7 上运行。两者的错误相同。

C# 浮点数 net-6.0 .net-7.0

评论

0赞 Ben Voigt 1/25/2023
数据对齐要求不会变得毫无用处,只是限制可以创建它们的字节偏移量。当然,如果在传入偏移量时检查这一点,而不是稍后尝试从中读取时任意出现,那就太好了。Span
0赞 Ben Voigt 1/25/2023
也就是说,C 和 C++ 处理从未对齐缓冲区中提取对象的方式是 。等效的 .NET 是 .memcpyBuffer.BlockCopy

答:

3赞 Ben Voigt 1/25/2023 #1

FluentModbus 在这里打破了对齐:

然后调用这在 ARM 上是一个问题,因为文档说MemoryMarshal.Cast

此方法仅在支持未对齐内存访问的平台上或通过其他方式对齐内存块时受支持。

ARM 不是一个支持未对齐内存访问的平台。

一个好的解决方法是分配一个 ,调用返回的版本 ,然后调用 。float[]ReadHoldingRegistersSpan<byte>CopyTo(MemoryMarshal.AsBytes(destFloatArray))

评论

0赞 Ingar Hjelle 1/26/2023
感谢您对我的问题进行澄清!尝试了您的解决方法,看起来效果很好。有效的新代码:var calibration = fluentClient.ReadHoldingRegisters(1, 8704, 4); float[] destFloatArray = new float[2]; calibration.CopyTo(MemoryMarshal.AsBytes<float>(destFloatArray)); Console.WriteLine("calibration K: " + destFloatArray[0]); Console.WriteLine("calibration B: " + destFloatArray[1]);