如果我分配一个像
size_t n = ???; unsigned char* s = malloc(n);
在s + i < s + j当且仅当i < j的意义上,将指向位置s + i的指针与0 <= i < n进行比较是否是完美定义的行为?可能是这样,但是一个人读到指针比较只在传染性数组中定义,对于初学者来说,不清楚上面分配的东西是否会算作“数组”,因为这个术语在C中也有正式的含义,而且一个人读到虚拟内存而没有完全消化,并开始担心。所以我想问一下确认一下。
s + i < s + j
i < j
s + i
0 <= i < n
i86rm4rw1#
从C标准(3.术语、定义和符号)3.15执行环境中数据存储的1个object区域,其内容可以表示值2注:当引用时,对象可以被解释为具有特定类型;见6.3.2.1。和(7.22.3存储器管理功能)1未指定连续调用aligned_alloc、calloc、malloc和realloc函数所分配的存储顺序和连续性。如果分配成功,则返回的指针被适当地对齐,使得它可以被分配给指向具有基本对齐要求的任何类型的对象的指针,然后用于访问所分配的空间中的这样的对象或这样的对象的数组(直到空间被显式地解除分配)。这段话在这里也很有用(6.2.5类型)20可以从对象和函数类型构造任意数量的派生类型,如下所示:
ccrfmcuu2#
C标准在这里有它的问题。因为从malloc返回的只是一个没有声明类型的内存块。从理论上讲,它还不是数组或任何其他类型。在实践中,编译器必须像对待数组一样对待它,否则整个C语言福尔斯就会分崩离析。在设计C99标准时,没有人想到这一点,从那时起,ISO C工作组一直回避解决这个问题。为了判断某个东西是否是有效的访问,我们需要知道它的类型,或者如果没有像malloc这样声明的类型,那么至少我们需要知道 * 有效类型 *,这是C标准与C99一起推出的一个系统,以解决这种情况。形式上,s指向没有声明类型的内存位置。C17 6.5 §6然后说:对于所有其他对没有声明类型的对象的访问,对象的有效类型只是用于访问的左值的类型。但是你不能访问它,所以它也没有有效类型。由于它既没有声明类型也没有有效类型,因此它也不能是某种类型的数组。在s上执行指针运算,而s不是数组,根据C17 6.5.6 §8,这是未定义的行为。除非您先访问它,从而将其标记为某种有效类型。显然,我们不能在这里逐字阅读C标准-它是破碎的。具体而言,它存在以下缺陷:
malloc
s
为了生成某种有意义的可执行文件,编译器因此忽略所有这些,并将malloc返回的任何内容视为数组。类似地,编译器倾向于在没有声明类型的区域上支持指针算法,否则C中与硬件相关的编程也是不可能的。总结一下:
号
是的,你总是可以在C中比较两个指针,不管它们指向哪里。但是你如何让指针指向这个没有类型的块,而不使用指针算术呢?
是的
2条答案
按热度按时间i86rm4rw1#
从C标准(3.术语、定义和符号)
3.15
执行环境中数据存储的1个object区域,其内容可以表示值
2注:当引用时,对象可以被解释为具有特定类型;见6.3.2.1。
和(7.22.3存储器管理功能)
1未指定连续调用aligned_alloc、calloc、malloc和realloc函数所分配的存储顺序和连续性。如果分配成功,则返回的指针被适当地对齐,使得它可以被分配给指向具有基本对齐要求的任何类型的对象的指针,然后用于访问所分配的空间中的这样的对象或这样的对象的数组(直到空间被显式地解除分配)。
这段话在这里也很有用(6.2.5类型)
20可以从对象和函数类型构造任意数量的派生类型,如下所示:
最后 *6.5.6加法运算符)
8当一个整数类型的表达式与指针相加或相减时,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,使得结果和原始数组元素的下标之差等于整数表达式。换句话说,如果表达式P指向数组对象的第i个元素,则表达式(P)+N(等价地,N+(P))和(P)-N(其中N的值为n)分别指向数组对象的第i+ n个元素和第i-n个元素,前提是它们存在。此外,如果表达式P指向数组对象的最后一个元素,则表达式(P)+1指向数组对象的最后一个元素之后的一个元素,如果表达式Q指向数组对象的最后一个元素之后的一个元素,则表达式(Q)-1指向数组对象的最后一个元素。如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象最后一个元素之后的元素,则计算不应产生溢出;否则,行为是未定义的。如果结果指向数组对象的最后一个元素之后的一个元素,则不应将其用作计算的一元 * 运算符的操作数。
ccrfmcuu2#
C标准在这里有它的问题。因为从malloc返回的只是一个没有声明类型的内存块。从理论上讲,它还不是数组或任何其他类型。在实践中,编译器必须像对待数组一样对待它,否则整个C语言福尔斯就会分崩离析。在设计C99标准时,没有人想到这一点,从那时起,ISO C工作组一直回避解决这个问题。
为了判断某个东西是否是有效的访问,我们需要知道它的类型,或者如果没有像
malloc
这样声明的类型,那么至少我们需要知道 * 有效类型 *,这是C标准与C99一起推出的一个系统,以解决这种情况。形式上,
s
指向没有声明类型的内存位置。C17 6.5 §6然后说:对于所有其他对没有声明类型的对象的访问,对象的有效类型只是用于访问的左值的类型。
但是你不能访问它,所以它也没有有效类型。由于它既没有声明类型也没有有效类型,因此它也不能是某种类型的数组。在
s
上执行指针运算,而s
不是数组,根据C17 6.5.6 §8,这是未定义的行为。除非您先访问它,从而将其标记为某种有效类型。显然,我们不能在这里逐字阅读C标准-它是破碎的。具体而言,它存在以下缺陷:
为了生成某种有意义的可执行文件,编译器因此忽略所有这些,并将
malloc
返回的任何内容视为数组。类似地,编译器倾向于在没有声明类型的区域上支持指针算法,否则C中与硬件相关的编程也是不可能的。总结一下:
号
是的,你总是可以在C中比较两个指针,不管它们指向哪里。但是你如何让指针指向这个没有类型的块,而不使用指针算术呢?
是的