跳转至可变修改类型/指向VLA的指针声明前的类型有效性问题
关于可变修改类型指针与goto跳转的类型合法性分析
针对你提出的问题:跳转后p指向的可变修改类型对象不会“丢失类型”,因为C语言的类型是编译期概念,而非运行时存在的实体;同时你的示例代码在标准框架下是合法的,以下是具体分析:
核心概念澄清
- 可变修改类型(VM类型):指包含变长数组(VLA)或指向VLA的指针等依赖运行时表达式确定维度的类型。标准明确VM类型的声明会在其所在的块作用域内完成类型绑定,但指针变量的存储(自动存储期)是在块开始时分配的——这是编译期对栈空间的规划,与类型确定无关。
- 类型的本质:C语言中不存在运行时的“类型信息”,所有类型检查、内存访问规则都是编译期确定的。不存在“跳转导致类型丢失”这种运行时行为,问题本质是跳转后的代码是否符合标准的语法/语义规则。
示例代码逐段分析
{//Contrived Example #define SIZE 4 int n=SIZE; int(**p)[n]=nullptr; // p是指向“指向int[n]的指针”的指针,属于VM类型 HERE:// 跳转目标在p的声明之后,p2a的声明之前 if(p){ /*do something that involves accessing p2a*/ printf("%d", (**p)[0]); return;} int arr[SIZE]={1,2,3,4}; // 普通数组,非VLA int(*p2a)[n]=&arr; // p2a是指向int[n]的指针,VM类型,此处完成类型绑定 p=&p2a; goto HERE; }
- 第一次跳转前的执行流程:
- 块开始后,编译期已规划好p、n、arr、p2a的栈空间分配,与代码中的声明顺序无关。
- p被初始化为
nullptr,执行到goto HERE时,p2a尚未被赋值,但跳转后if(p)条件为假,不会执行访问**p的代码,因此不会触发未定义行为。
- 第二次跳转的合法性:
- 当p被赋值为
&p2a后,p的类型(int(**)[n])与p2a的类型(int(*)[n])完全兼容,编译期已验证该赋值的合法性。 - 跳转回
HERE时,p非空,此时**p等价于*p2a,而*p2a的类型是int[n](n的值为4),与arr的int[4]类型兼容,因此(**p)[0]就是arr[0],访问完全合法。
- 当p被赋值为
标准规则依据
- C11标准6.8.6.1p1:
goto语句不能从可变修改类型标识符的作用域外跳转到作用域内,但你的跳转始终在p的作用域内,且跳转后未在p2a的作用域外访问p2a,符合规则。 - C11标准6.7.6.2p5:可变修改类型可以在块作用域内声明,其类型的确定在声明点完成,但变量存储的分配是块开始时的行为,二者互不冲突。
内容的提问来源于stack exchange,提问作者genek2
相关产品推荐
相关产品推荐

