【问题标题】:Pointer arithmetic in C adding and subtracting wrongC中的指针运算加法和减法错误
【发布时间】:2015-10-09 21:18:37
【问题描述】:

现在我有一个代码可以像这样进行指针运算

var1 + sizeof(structA)

Var1 是一个指针,而 structA 是一个 sizeOf 4 字节的结构。问题是,当我这样做时,地址被向下移动了 16 个字节而不是 4 个。我发现问题是因为在 C 中,即使我键入它实际上是

var1 + sizeof(structA) * sizeof(int)

as int 是 sizeof 的返回值。有没有办法解决这个问题? 对于类似的问题,我正在做

var1 - sizeof(structA)

但不是向上移动 16 个字节,而是向上移动 32 个字节,因此 0x10000032 变为 0x10000000。

有谁知道我该如何解决这个问题?

谢谢!

【问题讨论】:

  • var1 的完整类型是什么? (我猜structA *)。
  • “所以 0x10000032 变为 0x10000000” - 这是一个 50 字节的变化。
  • 如果你想修复它,你肯定需要先了解the pointer arithmetics in C
  • 对不起,我打错了。它是 0x10000004 变成 0x0FFFFFFC,所以 8 字节变化。 @PhilipKendall 是的,它是 structA *

标签: c pointers pointer-arithmetic


【解决方案1】:

不要使用var1 + sizeof(structA),而是使用var1 + 1

指针算术被定义为指针的数值根据对象类型的大小递增(和递减)。

因此,var1+1 的数值与var1 + sizeof(*var1) 的数值相同。

var1-1的数值与var1-sizeof(*var1)的数值相同。

示例程序

#include <stdio.h>

struct FiftyBytes
{
   char d[50];
};

struct FortyBytes
{
   char d[40];
};

void test1()
{
   struct FiftyBytes a[2];
   struct FiftyBytes* var1 = a;
   struct FiftyBytes* var2 = var1 + 1;
   printf("var1: %p, var2: %p\n", var1, var2);

   struct FiftyBytes* var3 = &a[1];
   struct FiftyBytes* var4 = var3 - 1;
   printf("var3: %p, var4: %p\n", var3, var4);
}

void test2()
{
   struct FortyBytes a[2];
   struct FortyBytes* var1 = a;
   struct FortyBytes* var2 = var1 + 1;
   printf("var1: %p, var2: %p\n", var1, var2);

   struct FortyBytes* var3 = &a[1];
   struct FortyBytes* var4 = var3 - 1;
   printf("var3: %p, var4: %p\n", var3, var4);
}

int main()
{
   test1();
   test2();
}

输出

var1: 0x22ca50, var2: 0x22ca82
var3: 0x22ca82, var4: 0x22ca50
var1: 0x22ca70, var2: 0x22ca98
var3: 0x22ca98, var4: 0x22ca70

如果您检查指针值的差异,您会注意到:

0x22ca82 - 0x22ca50 = 0x32 = 50
0x22ca98 - 0x22ca70 = 0x28 = 40

【讨论】:

  • 我知道我可以这样做,但我想保留它 sizeof(structA) 以防万一将来 structA 大小增加/减少,那么我的代码仍然可以工作
  • 还有,我该怎么做减法?我测试了它,10000004 (var1) - 1 返回 0ffffffc,这意味着它减去了 32 S:
  • @MoJo 增加 structA 的大小没关系。当你重新编译它时,它会将地址增加正确的字节数。
【解决方案2】:

您可以执行以下操作

((char*)var1) + sizeof(structA)

【讨论】:

  • 呃。为什么会有人想这样做??
  • @void_ptr 例如,有时您已经从磁盘读取了文件头,并且想跳过它。
  • @MarkRansom 是的,这正是我这样做的原因。我需要它跳过内存块的标题以转到内存块(它用于我正在处理的内存分配程序)
  • @MarkRansom - 我认为将不是structA数组的东西放入structA *var1指向的内存块中在概念上是错误的。
【解决方案3】:

在 C 中,表达式ptr + ival,其中ptr 是一个T* 指针,指向T[] 类型数组的第n 项,ival 是整数类型,根据定义是 指向同一数组的第 (n+ival)-th 项的指针(假设结果索引落在数组长度内)。所以对于

char  b[7];
char *pb = &b[2];
char *qb = pb+3;

指针qb 指向b[5],而为

long  l[7];
long *pl = &l[2];
long *ql = pl+3;

指针ql 指向l[5]。编译器根据指针类型自动识别数组中long 项中byte 的实际大小。

因此,将整数值添加到指针对应于将指针移动指定的元素数(元素的大小由指针的类型知道),而不是通过给定的数内存中的字节数。
类似地,从指针值中减去一个整数值会产生一个指针向后移动给定的项目数(不是字节)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-01
    • 2018-04-10
    • 1970-01-01
    • 2011-04-01
    • 2017-01-28
    • 1970-01-01
    相关资源
    最近更新 更多