【问题标题】:Lack of access specifer & in C does not result in a compile errorC 中缺少访问说明符 & 不会导致编译错误
【发布时间】:2016-03-11 12:09:54
【问题描述】:

在C语言中,当scanf()中的参数不存在&时,不会产生编译错误;相反,显示的结果是错误的(即出现语义错误)。

考虑以下代码:

char str[30];
int a;
printf("Enter the value");
scanf("%s %d", str, a);       // This is the statement in question.
printf("You entered %s %d", str, a);

这里我知道str 是一个字符数组,所以它会有一个基地址,因此不会产生编译错误。但是为什么a 参数没有& 不会导致编译错误呢?

同样str 给出正确的输出,但整数总是产生值 -28770 作为输出。这是为什么呢?

【问题讨论】:

  • 你在输入什么?你期望输出什么?
  • “整数总是将 -28770 作为输出” - 未初始化的局部变量 a。包含声明之前该内存位置(堆栈或寄存器)的任何内容。每次运行可能相同,每次运行可能不同;这就是为什么它是“未定义的行为”。 - 你的编译器没有警告你吗?
  • 好的。并且编译器没有给出任何警告。感谢您的回答。

标签: c string pass-by-reference access-specifier


【解决方案1】:

scanf 有原型:

int scanf(const char *fmt, ...);

... 表示在fmt 之后可以指定任意数量的任何类型 的参数。因此,调用者而不是编译器有责任确保提供的参数与函数所期望的匹配。

【讨论】:

    【解决方案2】:
    int scanf(const char *format, ...);
    

    这是 scanf 的原型。第一个参数是 char*,其他参数是可变长度。所以不会产生错误。

    【讨论】:

    • 详细说明:scanf() 中的可变参数没有声明类型,因此对于编译器来说,绝对可以是任何东西。
    【解决方案3】:

    正如 Umamahesh P 所写,您不会收到编译错误,因为 scanf 是一个变量参数函数。至于运行程序时会发生什么,这就是 C 标准所说的“未定义行为”。任何事情都有可能发生。您需要查看机器指令和内存地址级别发生的情况,以了解 scanf 对您提供的整数值而不是指针的确切作用。

    【讨论】:

    • 不会scanf(..., a) 甚至尝试将值输入写入内存中的随机位置,可能会出现段错误?
    • @HannoBinder 可能会发生 - 但行为是 未定义,这意味着任何事情都可能发生。
    • @HannoBinder:正如 davmac 所写,这可能会发生,但不能保证。我看到的另一种行为是参数在寄存器中传递,而 32 位整数和 64 位指针在不同的寄存器中传递,所以 scanf 会得到一个指针,该指针恰好在正确的寄存器中。跨度>
    • @ThomasPadron-McCarthy 感谢您提供有趣的见解。
    【解决方案4】:

    您可能会收到编译器警告,具体取决于您使用的编译器以及您指定的选项。

    此外,即使它试图显示这些警告,如果您使用 vscanf() 或使用动态字符串作为格式参数,您的编译器也将完全无法做到这一点。

    例如,这是我使用 mingw-64 gcc 4.5.4 得到的输出:

    gcc -Wall -o small.exe small.c
    
    small.c:7:3: warning: format '%d' expects type 'int *', but argument 3 has type 'int'
    small.c:7:8: warning: 'a' is used uninitialized in this function
    

    只需添加 -Werror 选项即可将这些警告变为错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-16
      • 1970-01-01
      • 2014-06-10
      • 2014-10-12
      相关资源
      最近更新 更多