c - 从数组中读取两个 int 作为 long

标签 c arrays pointers microcontroller

我正在从事一个微 Controller 项目,其中有一组来自通信接口(interface)的无符号整数。为了方便起见,可以通过定义宏来访问它们。

我需要发送一些无符号的 long 值,而不是必须处理来自通信寄存器的两个值并将它们转移到辅助 long 寄存器中,使用指针并从数组中读取两个值是否安全一次。

我有兴趣这样做,因为 Controller 上的处理资源非常有限。这安全吗,数组值在内存中总是连续的吗?

示例代码

...

unsigned int comms[MAX_ADDRESS];

...

#define FOO             comms[0]
#define BAR             comms[1]
#define VAL_1           comms[2]
#define VAL_1_EXT       (*(unsigned long*)(&comms[2])) // Use pointer trickery to read a long
#define VAL_2           comms[4]
#define VAL_2_EXT       (*(unsigned long*)(&comms[4]))

...

不确定它是否相关,但它是来自 TI 的 MSP430 系列的芯片,编译器版本 TI 4.3.3

最佳答案

这取决于您所说的“安全”是什么意思。从某种意义上说,这是绝对不安全的,因为 C 标准没有说明会发生什么,因为您正在使用指针转换别名类型。这是不可携带的。

但不可移植并不意味着没有功能。如果代码不用于生产,并且您可以很好地控制开发环境,那么您的建议很可能做得很好。 C 标准确实保证数组元素是连续的。如果编译器生成的代码在一个实例中从通用寄存器获取两个(我猜)16 位数量以正确形成 32 位长,那么几乎可以肯定:

  • 它将在所有用法中这样做。

  • future 的编译器版本也会这样做。

没有任何保证,但实际上这是一个合理的赌注。

要了解您获得的代码是否正确,请使用 -S 进行编译并检查。写一个好的测试来验证。

无论如何,您已经采取了一种很好的方法,通过在宏中隔离访问代码(尽管您应该去掉末尾的分号)。

以下宏关于 C 标准的明确定义。

#define VAL_1_EXT       (((unsigned long)comms[3] << 16) | (unsigned long)comms[2])

如果你写了

unsigned long x = VAL_1_EXT;

一个好的优化编译器应该使用上面的宏生成与您提出的宏相同的代码。我猜你是说它不是一个好的优化编译器。

正如评论中所指出的,这个宏不是左值。您不能将分配给它。为此,您需要一个单独的宏。

#define SET_VAL_1_EXT(Val) do { \
  unsigned long x = (unsigned long)Val;
  comms[2] = x; \
  comms[3] = (unsigned)(x >> 16); \
} while (0)

关于c - 从数组中读取两个 int 作为 long,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25319712/

相关文章:

c - C 中不同 char** 的指针

c - 传递指向函数的指针没有按预期工作

buffer-overflow - 如何将没有对应 ASCII 的十六进制字符作为输入传递给 C 程序

c - 如何在C中检查它是否是链表的子集

c - 基于比特选择的算法效率

c++ - 按值传递时更改整数数组的大小

java - 代码较短,因此用相同的值填充数组

javascript - 在数组中查找子数组

c++ - 从 vector 的元素成员方法插入 vector 元素 destroys *this

c - 以 r+ 模式写入的额外空格