You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言中数组下标与指针算术运算结果不同的原因探究

为什么数组下标语法取地址得到无效地址,而指针算术却正常?

在C语言中,使用数组下标语法获取数组元素地址时得到了无效地址,但用指针算术运算却能得到预期的正确地址,核心原因在于无符号整数的溢出特性和数组下标表达式的运算规则,结合代码示例分析如下:

问题复现代码(变量arg版本)

编译环境:gcc C99/C11标准,编译选项-Wall -O0

#include <stdio.h>

int main() {
    unsigned int arg = 0;
    char         arr[5] = {'a', 'b', 'c', 'd', 'e'};
    char*        arrp   = arr + 2;
    char*        pos_1  = arrp - arg - 1;
    char*        pos_2  = &arrp[-arg - 1];
    printf("arr:  %p\narrp: %p\npos_1:%p\npos_2:%p\n", arr, arrp, pos_1, pos_2);
    return 0;
}

运行结果

arr:  0x7fff31035a73
arrp: 0x7fff31035a75
pos_1:0x7fff31035a74
pos_2:0x800031035a74

可以看到pos_2的地址明显无效(高位多了0x8000)。

常量替代后的正常代码

当用常量0代替变量arg时,pos_2能得到正确地址:

#include <stdio.h>

int main() {
    char         arr[5] = {'a', 'b', 'c', 'd', 'e'};
    char*        arrp   = arr + 2;
    char*        pos_1  = arrp - 0 - 1;
    char*        pos_2  = &arrp[-0 - 1];
    printf("arr:  %p\narrp: %p\npos_1:%p\npos_2:%p\n", arr, arrp, pos_1, pos_2);
    return 0;
}

运行结果

arr:  0x7ffc270c4ed3
arrp: 0x7ffc270c4ed5
pos_1:0x7ffc270c4ed4
pos_2:0x7ffc270c4ed4

原因分析

  1. 无符号整数的运算特性:
    arg是unsigned int类型,C语言中无符号整数的运算遵循模2^n规则,不存在负数。当计算-arg -1时,-arg会被转换为对应无符号类型的最大值(比如32位unsigned int是0xFFFFFFFF),再减1得到0xFFFFFFFE——这是一个极大的正数,而非预期的-1。

  2. 数组下标表达式的等价规则:
    C标准规定,arrp[N]等价于*(arrp + N),因此&arrp[N]本质就是arrp + N。在&arrp[-arg -1]中,N即-arg -1,由于arg是无符号数,整个表达式的结果是无符号类型的极大值,将这个值作为偏移量加到arrp上,直接导致指针地址溢出,得到无效的高位地址。

  3. 指针算术运算的运算顺序与类型转换:
    对于arrp - arg -1,运算顺序是(arrp - arg) - 1:

    • 第一步arrp - arg:arrp是char*类型,arg是unsigned int(值为0),会触发寻常算术转换,指针地址被转换为对应宽度的无符号整数类型,减去0后仍等于arrp的地址;
    • 第二步减1:这里的1是int类型,指针减去1等价于向前偏移一个char的长度,结果正确。
  4. 常量编译期优化的影响:
    当arg是常量0时,编译器在编译期就能直接计算出-0 -1 = -1,这个值是有符号整数,此时arrp + (-1)等价于arrp -1,自然得到正确地址。

内容的提问来源于stack exchange,提问作者Newb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 01:30:37