是否使用对 C 中定义的内部数组的引用来访问外部多维数组?

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

考虑以下代码:

void process(int *);

int func(void) {
    int arr[2][2] = {{1,2},{3,4}};
    process(arr[0]);
    return arr[1][0];
}

假设函数

process
是用汇编语言实现的。

访问多维数组的元素是否越界未定义行为?中所述,使用

arr[1][0]
访问元素
arr[0][2]
是未定义行为,通过指针算术应指向相同的内存位置。

编译上述代码的 C 编译器是否可以假设

arr[1][0]
在调用
process
后保持不变,因此例如:将最后一行优化为
return 3;
,因为
process
函数只能访问
arr[0][0]
arr[0][1]

但是,如果编译器假设

process
首先在内部将
arr[0]
转换为
int[2][2]
指针,这可能不是未定义的行为,类似于常见的
container_of
宏如何使用指向结构体的指针来访问结构体指针。成员值,因此编译器将不被允许执行上面的优化?

c language-lawyer
1个回答
0
投票

编译器应该从数组中读取数据。这就是语言所要求的。所以你不必太担心你期望的错误。

用常量替换数组访问不是特定于语言的,而是特定于编译器的。大多数当前的编译器都足够聪明,可以正确执行此操作。

为了获得更好的图片,请尝试编译以下代码:

#include <stdio.h>

void process(int *p) {
    p[2] = -1;
}
void process2(int *p);


int main() {
    int arr[2][2] = {{1,2},{3,4}};
    printf("%d\n", arr[1][0]);
    process(arr[0]);
    printf("%d\n", arr[1][0]);

    int arr2[2][2] = {{5,6},{7,8}};
    printf("%d\n", arr2[1][0]);
    process2(arr2[0]);
    printf("%d\n", arr2[1][0]);

    return 0;
}

无需任何优化 (

gcc -S foo.c
),您可以在堆栈上有两个数组,并从数组中读取四次,再加上一个带有主体的实际
process
函数。

但是一旦你打开优化器(

gcc -S -O1 foo.c
),你可以看到第一个数组完全消失,只剩下
process
函数的标签。打印前两个
printf
中的常量,在堆栈上为
arr2
定义一个数组,然后是常量的
printf
,调用
process2
,最后从数组中定义
printf

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