将索引访问转向指针访问

时间:2016-10-16 10:38:49

标签: c language-lawyer

假设我有一个访问的函数int access_p_i(uintptr_t i) p[i]其中char *p;是全局变量。

char *p;
int access_p_i(uintptr_t i)
{
    return printf("p[%lx]=%c\n", i, p[i]);
}

预期用途如下:

char buf[] = "abcde";
p = buf; /*set p once*/
access_p_i(3); //prints p[3]=d
access_p_i(2); //prints p[2]=c

说我想劫持它(不修改函数)来获取绝对指针:

memset(&p,0,sizeof(char*)); /*set p once*/
access_p_i((uintptr_t)"d");
access_p_i((uintptr_t)"c");

这是便携式和合法的C吗?

3 个答案:

答案 0 :(得分:2)

不,我认为没关系。从ANSI / ISO 9899-1990开始,向指针添加或从指针中减去一个整数:

  

如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出;否则,行为未定义。除非指针操作数和结果都指向同一个数组对象的元素,或者指针操作数指向一个超过数组对象的最后一个元素并且结果指向同一个数组对象的元素,否则如果result用作一元*运算符的操作数。

答案 1 :(得分:1)

索引访问背后的数学将继续有效,因为索引a[b]是写*(a+b)或其等效*(b+a)的另一种方式,导致正常p[i]之间的奇数等价并倒置i[p]

但是,此代码不可移植,因为标准无法保证char*可以毫无损失地转换为size_t

  

如果我将所有size_t替换为uintptr_t

,该怎么办?

假设您的目标系统上有uintptr_t,则需要使用memset(&p,0,sizeof(char*))分配更改p = (char*)(uintptr_t)0来电。但是,在大多数系统上都不重要。

答案 2 :(得分:0)

ISO / IEC 9899:1999 7.18.1.4说intptr_tuintptr_t是可选的,并且在7.18 / 4中:

  

实施应提供描述为" required"的那些类型,但不需要提供任何其他类型(描述为"可选")。