在C语言中,是否可以保证数组的起始地址小于其他元素的地址? [英] In C, is it guaranteed that the array start address is smaller than the other elements' addresses?

查看:94
本文介绍了在C语言中,是否可以保证数组的起始地址小于其他元素的地址?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

换句话说,做

index = &array[x] - &array[0];

是否始终(按照C标准)保证& array [0]< =& array [x],还是取决于编译器? 与该主题相关的C标准章节是什么?

Is it always guaranteed (per C standard) that &array[0] <= &array[x], or is it dependent on the compiler? What are the C standard chapters relevant for this topic ?

推荐答案

保证地址顺序.关系运算符的行为在 C11 6.5.8p5 :

The address ordering is guaranteed. The behaviour of relational operators is defined in C11 6.5.8p5:

[...]下标值较大的数组元素的指针比下标值较低的相同数组元素的指针更大. [...]

[...] pointers to array elements with larger subscript values compare greater than pointers to elements of the same array with lower subscript values. [...]

因此,如果x是元素的索引或大于最大索引的元素,则&array[x] >= &array[0]始终为true. (如果x不是元素的索引,也不是实际数组末尾的索引,则行为是不确定的.)

Thus &array[x] >= &array[0] is true always if x is the index of an element, or one greater than the maximum index. (And if x is not the index of an element, or one past the end of the actual array, then behaviour is undefined.)

但是令人惊讶的是,差异 &array[x] - &array[0]仅在

时定义,当

But surprisingly the difference &array[x] - &array[0] is defined only when

  • x是元素的实际索引,或者比数组
  • 中的最大索引大一个
  • x不大于PTRDIFF_MAX
  • x is an actual index of an element or one greater than the maximum index in the array and
  • x is not greater than PTRDIFF_MAX

因为有一个特殊的极端情况: C11 6.5.6p9 表示

as there is a peculiar corner case: C11 6.5.6p9 says that

9当减去两个指针时,两个指针均应指向同一数组对象的元素,或者指向数组对象的最后一个元素;结果是两个数组元素的下标不同. 结果的大小是实现定义的,其类型(有符号整数类型)是在<stddef.h>标头中定义的ptrdiff_t.如果结果无法在该类型的对象中表示,则行为是不确定的.换句话说,如果表达式P和Q分别指向数组对象的第i个元素和第j个元素,则表达式(P)-(Q)的值为 ij,前提是该值适合类型为ptrdiff_t的对象. [...]

9 When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. The size of the result is implementation-defined, and its type (a signed integer type) is ptrdiff_t defined in the <stddef.h> header. If the result is not representable in an object of that type, the behavior is undefined. In other words, if the expressions P and Q point to, respectively, the i-th and j-th elements of an array object, the expression (P)-(Q) has the value i-j provided the value fits in an object of type ptrdiff_t.[...]

如果带符号的ptrdiff_t与未带符号的size_t具有相同的宽度,则可能有一个数组,该数组的索引x大于PTRDIFF_MAX;那么&array[x] >= &array[0]仍然,但是&array[x] - &array[0]完全没有定义的行为.

If the signed ptrdiff_t is of same width as the unsigned size_t, it is possible to have an array for which there exists an index x greater than PTRDIFF_MAX; then &array[x] >= &array[0] still, but &array[x] - &array[0] has completely undefined behaviour.

这是一个示范.我的计算机是运行64位Ubuntu Linux的x86-64,但它也能够运行32位程序.在32位X86 Linux + GCC中,ptrdiff_t是32位有符号整数,而size_t是32位无符号整数.在64位Linux上以32位模式运行的程序可以轻松地使用malloc分配超过2G的内存,因为整个4G地址空间都是为用户模式保留的.

Here is a demonstration. My computer is x86-64 that runs 64-bit Ubuntu Linux, but it is also capable of running 32-bit programs. In 32-bit X86 Linux + GCC, ptrdiff_t is a 32-bit signed integer, and size_t is 32-bit unsigned integer. A program run in 64-bit Linux in 32-bit mode can easily allocate over 2G of memory with malloc, as the entire 4G address space is reserved for user mode.

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stddef.h>

int main(void) {
    size_t size = (size_t)PTRDIFF_MAX + 2;
    size_t x = (size_t)PTRDIFF_MAX + 1;
    char *array = malloc(size);
    if (! array) {
        perror("malloc");
        exit(1);
    }
    array[0] = 42;
    array[x] = 84;
    printf("&array[0]: %p\n", (void *)&array[0]);
    printf("&array[x]: %p\n", (void *)&array[x]);
    printf("&array[x] >= &array[0]: %d\n", &array[x] >= &array[0]);
    printf("&array[x] - &array[1]: %td\n", &array[x] - &array[1]);
    printf("&array[x] - &array[0]: %td\n", &array[x] - &array[0]);
    printf("(&array[x] - &array[0]) < 0: %d\n", (&array[x] - &array[0]) < 0);
}

然后编译为32位模式并运行:

Then compiled for 32-bit mode and run:

% gcc huge.c -m32 -Wall && ./a.out 
&array[0]: 0x77567008
&array[x]: 0xf7567008
&array[x] >= &array[0]: 1
&array[x] - &array[1]: 2147483647
&array[x] - &array[0]: -2147483648
(&array[x] - &array[0]) < 0: 1

已成功分配内存,起始地址为0x77558008,&array[x]0xf7504008&array[x]大于&array[0].差异&array[x] - &array[1]产生了积极的结果,而&array[x] - &array[0]具有不确定的行为,现在却产生了消极的结果!

The memory was allocated successfully, the starting address is at 0x77558008, &array[x] is at 0xf7504008, &array[x] is greater than &array[0]. The difference &array[x] - &array[1] produced a positive result, whereas &array[x] - &array[0], with its undefined behaviour, now produced a negative result!

这篇关于在C语言中,是否可以保证数组的起始地址小于其他元素的地址?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆