C++中的指针被用作数组,无需初始化或分配。然而它有效并且被认为是有效的做法

问题描述 投票:0回答:1

我今天遇到了这段代码:

ushort *LibRaw::ljpeg_row(int jrow, struct jhead *jh)
{
  ushort mark = 0, *row[3];
  // Irrelevant code here...
  FORC3 row[c] = jh->row + jh->wide * jh->clrs * ((jrow + c) & 1);
  // Irrelevant code here...
  return row[2];
}

void LibRaw::canon_sraw_load_raw()
{
  short *rp = 0, (*ip)[4];
  // Irrelevant code here...
  rp = (short *)ljpeg_row(jrow++, &jh);
  // Few lines of code with no assignment to any variable...
  FORC(jh.clrs - 2)
  {
     ip[col + (c >> 1) * width + (c & 1)][0] = rp[jcol + c];
     ip[col + (c >> 1) * width + (c & 1)][1] =
     ip[col + (c >> 1) * width + (c & 1)][2] = 8192;
  }
  // Irrelevant code here...
}

让我们将

ljpeg_row
函数作为被调用者,将
canon_sraw_load_raw
作为调用者。据我了解,变量
row
是一个 ushort 指针数组,长度为 3。这在被调用者内部以有效的方式使用。但是,在按值返回数组的单个元素后,调用者将遍历此指针 (
rp
),因为它是一个数组!
FORC
/
FORC3
宏扩展为 for 循环,递增
c
。在我的示例中,
FORC(jh.clrs - 2)
c
至少递增一次。

现在我的问题:

  • 是否应该在被调用者内部使用 alloc/malloc 进行分配,或者在调用者函数中将其声明/初始化为数组,以免导致分段错误?无法保证(除了这些行之间没有其他分配的事实)
    rp[jcol + c]
    不会有垃圾。
  • 据我了解,程序员实际上没有办法控制
    row
    数组分配在哪里,不仅尝试触摸它,而且还尝试从那里读取有用的数据?!所以,
  • 这是一种有效的编程风格吗?这是一些有效的快速技巧吗?

这是一个著名的开源库,有很多贡献者,所以我很犹豫这是不是一个错误(因此要打开一个新的 github 问题并询问)。此外,它可以正常编译和运行,没有分段错误。此外,我检查了 git repo,上面的代码是从 6 年前的第一次提交开始的。然而我们就在这里。我在这里缺少什么?

我已经编译并运行了代码。运行没有问题。 我已经完成了我的橡皮鸭调试,但我无法看透这一点! 我搜索了类似的问题,例如:

https://stackoverflow.com/questions/12416459/can-i-use-a-void-pointer-in-c-as-an-array

https://stackoverflow.com/questions/59184633/c-declaring-a-pointer-and-then-use-it-as-an-array-memory-allocation

https://stackoverflow.com/questions/43724654/how-is-this-variable-used-as-an-int-and-as-an-array-in-cpp

只是进一步验证我的问题。

这是原始文件的链接(如果您想检查我已删除的代码): https://github.com/LibRaw/LibRaw/blob/master/src/decoders/decoders_dcraw.cpp

c++ arrays pointers allocation
1个回答
0
投票

将指向单个项目的指针视为数组是一种常见的做法,但根据静态分析器,它不是“有效的”。

让我们考虑一个 3 槽阵列,

a
:

     +---+---+---+  
a[3] | 0 | 1 | 2 |  
     +---+---+---+  

我们不知道数组末尾后面是什么。 访问

a[3]
是未定义的行为。

鉴于:

int * p = &a[2];  // Valid location  

我们毫无疑问地知道,

p
指向单个项目。
我们可以增加指针
p
,但我们不能保证它指向有效的位置。
++p; // Valid operation of incrementing a pointer.

有效位置的测试是指针被取消引用时。 在此上下文中有效意味着该位置有可读内存。 然而,指针

p
现在有可能指向一个不包含任何内存的地址。 在这种情况下,引用将调用未定义的行为

当使用指向不再指向有效对象的单个对象的指针时,会做出许多假设(例如通过递增)。 这些假设可能有效,也可能无效。 您所能保证的是指向单个对象的指针对该对象有效;对修改后的指针的任何取消引用都是未定义的行为

© www.soinside.com 2019 - 2024. All rights reserved.