C-指针减法,32位的臂,负距离为负距离



执行指针的减法时,第一个指针小于第二个指针时,我的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将具有值0x7FD5395CCPSR寄存器的N位为0,表明结果不是负

Windows 7计算器应用程序报告为负,但仅在表示为64位时:FFFFFFFF7FD5395C

作为实验,我将ptrdiff_t类型用于长度,并生成了相同的组装语言。

问题:

  1. 是这种有效的行为,以指针减法的结果下流?
  2. 建议将距离视为负的推荐数据类型?

平台:
目标处理器: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];

最新更新