在C语言中跳进一个街区

在C语言中跳进一个街区,c,static,goto,C,Static,Goto,如果我跳进这个例子中的块,跳过声明 #include <stdio.h> int main(int argc, char *argv[]){ int counter = 0; goto jump; { static int st = -9; int au = -9; jump: printf("st = %d\n", st); printf("au = %d\n", au); au++; st++; counter

如果我跳进这个例子中的块,跳过声明

#include <stdio.h>

int main(int argc, char *argv[]){
  int counter = 0;
  goto jump;
  {
    static int st = -9;
    int au = -9;
jump:
    printf("st = %d\n", st);
    printf("au = %d\n", au);
    au++;
    st++;
    counter++;
  }

  if(counter < 10) goto jump;

  return 0;
}
#包括
int main(int argc,char*argv[]){
int计数器=0;
去跳;
{
静态int st=-9;
int au=-9;
跳转:
printf(“st=%d\n”,st);
printf(“au=%d\n”,au);
au++;
st++;
计数器++;
}
如果(计数器<10)跳转;
返回0;
}
我可以用gcc--std=c89-pedantic编译它

似乎您无法真正跳过声明:变量仍然被声明,即使声明的行从未到达

但不知何故,你可以跳过定义

  • st
    作为一个静态变量,使用值-9进行初始化,并计数到0
  • au
    使用值0初始化,并最多计数9

  • 是1。和/或2。在调用
    main()
    之前,在程序启动时初始化
    st
    等静态变量,即使是作用域为函数或块的静态变量,C标准要求的一种行为。跳过声明/初始值设定项不会影响这一点,因此对于此特定场景,不会发生未定义、未指定或不确定的行为

    对于自动变量,例如
    au
    ,当在执行块时达到声明时,就会进行初始化。由于
    goto
    跳过了块执行的该部分,因此
    au
    的值保持不确定,并且在这种情况下使用变量的值而不首先将其设置为某个确定值是未定义的行为

    请注意,C++中的一些细节是不同的。例如,C++标准称如果程序跳过声明,除非声明是POD类型,声明不包含初始化器,否则程序就不正确。

    < P>(1)是,并且(2)是的,它将具有不确定的值。 参考文献:


    在C语言中,非静态变量的作用域定义为从声明变量的点到其封闭块的末尾,但其初始值设定项被视为语句。未设置为值的堆栈变量将具有不确定的值,类似于堆变量(使用
    malloc()
    分配)将具有分配内存位置中的任何垃圾值

    另一方面,始终声明
    静态
    变量(但只能在其自身的块中访问),并且基本上在程序启动时就用其初始化值填充,以便它一进入作用域就具有该值

    下面是一些手工编写的程序集,展示了C代码如何直接翻译。优化器将进行更改以使代码更小或更快,编译器将添加一些额外的标记和注释,用于调试、跟踪和其他目的。我可能没有完全正确的语法,但它足够接近我们的目的。

    请特别注意,
    st
    在代码本身中定义并给定一个值,而
    au
    保存在堆栈上,并且仅在代码为其指定值时才获取其值


    如果将
    au
    改为不带初始值设定项的全局变量(即线程本地),编译器将使用类型的默认值将
    au
    放入
    .data
    部分,在这种情况下,代码将如下更改:

    .data
    ;... other data lines
    au:            WORD    0            ;declaration and uninitialized (default) value of au
    
    .text
    ;... other instruction code lines
    sub    esp, 4        ;reserve 4 bytes for only counter
    
    ;... other instruction code lines
    jmp    jump          ;goto jump label
    mov    [au], -9      ;assign au (still skipped and ignored)
    jump:                ;label, same as in C
    ;... rest of program (references to au use [au] instead of -20[ebp]
    

    我的眼睛请不要用goto,这是一个非常糟糕的做法。在c语言开始时,由于从汇编代码迁移,它被大量使用,这导致了所谓的“意大利面代码”,以及实际上无法理解的程序。我知道这可能是出于好奇,但不要使用goto
    au
    在跳转后未初始化;您的printf语句会导致未定义的行为。@Mr.Branch Goto不是一个坏习惯。我们应该避免滥用goto。在linux内核中,有很多goto,goto可以在很多情况下清晰地编写代码。“未设置为值的堆栈变量通常预初始化为零。”这是错误的;它也不是你在第一段中所说的实现定义。@M.M你是对的。去展示我因失去记忆而得到的东西。我已经查阅了这些信息,并编辑了我的答案以更正这些陈述。
    .data
    ;... other data lines
    au:            WORD    0            ;declaration and uninitialized (default) value of au
    
    .text
    ;... other instruction code lines
    sub    esp, 4        ;reserve 4 bytes for only counter
    
    ;... other instruction code lines
    jmp    jump          ;goto jump label
    mov    [au], -9      ;assign au (still skipped and ignored)
    jump:                ;label, same as in C
    ;... rest of program (references to au use [au] instead of -20[ebp]