执行指针的减法时,第一个指针小于第二个指针时,我的ARM处理器会遇到底流错误。
示例代码:
#include <stdint.h>
#include <stdbool.h>
uint8_t * p_formatted_data_end;
uint8_t formatted_text_buffer[10240];
static _Bool
Flush_Buffer_No_Checksum(void)
{
_Bool system_failure_occurred = false;
p_formatted_data_end = 0; // For demonstration puposes.
const signed int length =
p_formatted_data_end - &formatted_text_buffer[0];
if (length < 0)
{
system_failure_occurred = true;
}
//...
return true;
}
IAR编译器生成的汇编代码为:
807 static _Bool
808 Flush_Buffer_No_Checksum(void)
809 {
Flush_Buffer_No_Checksum:
00000000 0xE92D4070 PUSH {R4-R6,LR}
00000004 0xE24DD008 SUB SP,SP,#+8
810 _Bool system_failure_occurred = false;
00000008 0xE3A04000 MOV R4,#+0
811 p_formatted_data_end = 0; // For demonstration purposes.
0000000C 0xE3A00000 MOV R0,#+0
00000010 0x........ LDR R1,??DataTable3_7
00000014 0xE5810000 STR R0,[R1, #+0]
812 const signed int length =
813 p_formatted_data_end - &formatted_text_buffer[0];
00000018 0x........ LDR R0,??DataTable3_7
0000001C 0xE5900000 LDR R0,[R0, #+0]
00000020 0x........ LDR R1,??DataTable7_7
00000024 0xE0505001 SUBS R5,R0,R1
814 if (length < 0)
00000028 0xE3550000 CMP R5,#+0
0000002C 0x5A000009 BPL ??Flush_Buffer_No_Checksum_0
815 {
816 system_failure_occurred = true;
00000030 0xE3A00001 MOV R0,#+1
00000034 0xE1B04000 MOVS R4,R0
减法指令SUBS R5,R0,R1
等于:
R5 = R0 - R1
如果结果为负,则将设置CPSR
寄存器中的N
位。参考:A4.1.106 ARM架构参考手册
让:
R0 == 0x00000000
R1 == 0x802AC6A5
寄存器R5
将具有值0x7FD5395C
。CPSR
寄存器的N
位为0,表明结果不是负。
Windows 7计算器应用程序报告为负,但仅在表示为64位时:FFFFFFFF7FD5395C
。
作为实验,我将ptrdiff_t
类型用于长度,并生成了相同的组装语言。
问题:
- 是这种有效的行为,以指针减法的结果下流?
- 建议将距离视为负的推荐数据类型?
平台:
目标处理器:ARM Cortex A8(TI AM3358)
编译器:IAR 7.40
开发平台:Windows 7.
这是有效的行为,以指针减去下油的结果吗?
是的,因为您案件中的行为不确定。任何行为在那里有效。如注释中所观察到的那样,仅针对指向同一数组对象元素的指针,或一个超过数组对象的最后一个元素(C2011,6.5.6/9)。
建议将距离视为负的推荐数据类型?
在定义的地方,减去两个指针的结果指定为ptrdiff_t
型,这是一种签名的整数类型的实现定义的大小。如果评估p1 - p2
,其中p1
指向数组元素,而p2
指向同一数组的后期元素,则结果将为一个负数为ptrdiff_t
。
尽管这是ub,如其他答案中所述,大多数C实现都会简单地减去这些指针的 ptrdiff_t
size(或可能对其单词大小使用适当的算术操作数为near
/far
/huge
指针)。结果应适合ptrdiff_t
,这通常是ARM上的Typedef-Ed int
:
typedef int ptrdiff_t;
因此,在这种特殊情况下,您的代码问题仅仅是您正在按照签名来处理unsigned int
值,并且不合适。如您的问题所示,formatted_text_buffer
的地址是0x802AC6A5
,它适合unsigned int
,但是(int)0x802AC6A5
的补充形式实际上是A pange> pangis 数字(-0x7FD5395B
)。因此,从0
中减去负数将按预期返回正int
。
签名的32位整数减法将正确工作,如果两个操作数均小于0x7FFFFFFF
,并且合理地期望您的数组小于此:
// this will work
const int length = &formatted_text_buffer[0] - &formatted_text_buffer[100];
或,如果您确实需要减去不适合签名的32位INT的指针,请改用long long
:
// ...but I doubt you really want this
const long long length = (long long)p_formatted_data_end -
(long long)&formatted_text_buffer[0];