【问题标题】:Can "printf" be used as a variable name?“printf”可以用作变量名吗?
【发布时间】:2021-06-20 19:55:33
【问题描述】:

C中变量名的规则如下:

  1. 变量名只能包含字母(大写和小写字母)、数字和下划线。
  2. 变量的第一个字母应该是字母或下划线。
  3. 对于变量名(标识符)的长度没有规定。但是,如果变量名超过 31 个字符,您可能会在某些编译器中遇到问题。 (来源:[https://www.programiz.com/c-programming/c-variables-constants])

我想知道理论上是否将single underbar(_)double underbar(__) 用作变量? printfscanf 可以用作变量吗?

在玩c编译器(Dev C++)和linux Ubuntu Vi时,即使我使用上面的作为变量名,也没有任何错误或警告。

我使用的代码如下:

#include <stdio.h>
int main(void){
   int scanf;
   int printf;
   int _;
   int __;
   return 0;
}

【问题讨论】:

    标签: c scope declaration identifier reserved-words


    【解决方案1】:

    是的,它们可以使用。见:

    代码:

    ~> cat demo.c
    #include <stdio.h>
    
    void show(int i) {
       printf("Just for show: %i\n", i);
    }
    
    int main(int argc, char **args) {
       int printf = 42;
       int _ = 11;
       int __ = 22;
    
       (void)argc;
       (void)args;
    
       show(printf);
       show(_);
       show(__);
    
       return 0;
    }
    

    没有错误的编译过程:

    ~>  gcc -std=c99 -Wall -Wextra -pedantic -o demo demo.c
    

    输出:

    ~>  ./demo
    Just for show: 42
    Just for show: 11
    Just for show: 22
    

    【讨论】:

    • 解释为什么可以使用它们可能很有用。 __ 示例也不符合要求。
    【解决方案2】:

    当您将 printf 初始化为变量名时,您不能再使用 printf 命令,与 scanf 一样。最初 printf 命令指向代码以获取输入,但现在您已将其分配给整数。

    【讨论】:

    • 你不能在同一个范围内。
    【解决方案3】:

    可以,这并不意味着你应该

    是的,___ 是有效的标识符,因为它们满足标识符规则。它们可能导致代码难以阅读,并且可能与实现中已经使用的名称发生冲突,因此您不应以这种方式单独使用它们。

    至于使用printfscanf 作为变量名,你只能在没有将它们声明为函数的情况下这样做 - 换句话说,你不能这样做如果你已经包含了stdio.h

    C 有四个 命名空间 用于标识符(或者,更准确地说,四类命名空间);如果它们属于不同的名称空间,则只能对同一范围内的两个不同事物使用相同的标识符。命名空间是:

    • 所有标签(通过goto 关键字或结尾的“:”消除歧义);
    • 所有标签名称(通过structenumunion 关键字消除歧义);
    • structunion 成员名称(通过 .-&gt; 运算符消除歧义;标识符可用于多种 structunion 类型)
    • 所有其他名称(变量名、函数名、枚举常量等)

    如果你已经包含了stdio.h,那么printfscanf已经被声明为函数名,所以你不能在那个范围内也将它们用作变量名,因为函数名和变量名属于相同的名称空间。但是,您可以将它们用作标签名称、成员名称或标签,尽管我强烈建议您不要这样做。

    【讨论】:

    • 关于“只有在没有将它们声明为函数时才能这样做”:内部作用域中的标识符可以隐藏外部作用域中的标识符。
    【解决方案4】:

    您可以在块范围内或在结构、联合或枚举的标记的名称空间中或在结构和联合成员的名称空间中或在函数原型范围内使用名称 scanfprintf

    在块范围内声明的名称如scanfprintf 将隐藏在文件范围内声明的相应函数名。但您不得在文件范围内重新声明这些名称。

    这是一个演示程序。

    #include <stdio.h>
    
    int main(void) 
    {
        int printf = 10;
    
        {
            int *scanf = &printf;
            extern int printf(const char * restrict format, ...);
        
            printf( "printf = %d\n", *scanf );
        }       
        
        return 0;
    }
    

    它的输出是

    printf = 10
    

    这是另一个演示程序,显示了使用名称 printf 的其他方式

    #include <stdio.h>
    
    struct printf
    {
        int printf;
    };
    
    void f( int printf );
    
    void f( int x )
    {
        printf( "x = %d\n", x );
    }
    
    int main(void) 
    {
        struct printf printf = { .printf = 10 };
        
        f( printf.printf );
        
        return 0;
    }
    

    程序输出是

    x = 10
    

    这样使用 printf 这个名字自然只会让代码的读者感到困惑。

    至于以下划线开头的名称则根据 C 标准(7.1.3 保留标识符)

    1 每个标头都声明或定义其列于其中的所有标识符 相关的子条款,并且可选地声明或定义标识符 在其相关的未来图书馆方向子条款中列出和 始终保留用于任何用途或用作 文件范围标识符。

    ——所有以下划线开头的标识符 大写字母或其他下划线始终保留给任何 使用。

    因此,您不能在文件范围或块范围内使用此声明中的标识符

    int __;
    

    名称由实现保留。

    至于你的代码sn-p中的这个声明

     int _;
    

    那么因为它没有文件范围(它有一个块范围),那么在声明中使用的标识符(使用这个标识符的声明)是有效的。

    但是,如果您将在文件范围内声明名称,例如

     int _;
    
     int main( vpid )
     {
         //...
     }
    

    那么这样的标识符声明将是无效的。

    你也不能在文件范围内使用这样的标识符作为标签名。例如

    struct _
    {
        int x;
    };
    
    int main( void )
    {
        //...
    }
    

    ——所有以下划线开头的标识符总是被保留 在普通和标签中用作具有文件范围的标识符 命名空间。

    【讨论】:

      【解决方案5】:
      • 变量的第一个字母应该是字母或下划线。

        使用下划线是不好的做法,因为这样的名称可能会与编译器库头​​文件中的内部冲突。 C 标准 7.1.3 规定:

        以下划线和大写字母或另一个下划线开头的所有标识符始终保留供任何使用。

      • 变量名(标识符)的长度没有规定

        不正确,列出了关于编译器跟踪多少个字母的限制。在当前标准中,外部标识符为 31 个字母,内部标识符为 63 个。在称为 C90 的旧版 C 中,这些限制对于外部标识符只有 6 个字母,这简直是疯了。如果您倾向于使用过时的编译器,则需要非常小心。 (Dev C++ 已经过时,但在这种情况下有点安全。)

      printf 或 scanf 可以用作变量吗?

      理论上,您可以在本地范围内这样做。 7.1.3 进一步说明:

      以下任何子条款(包括未来的库方向)中列出的每个具有文件范围的标识符都保留用作宏名称和在同一名称空间中作为具有文件范围的标识符,如果包括其任何关联的标头.

      这意味着您不能在文件范围内声明名为printf 的变量或函数,但您可以在本地范围内这样做。当然,现在人们确实为了“函数模拟”而一直声明名为 printf 的宏,所以实际上它是无害的。

      但一般的经验法则是:如果你做了非常奇怪的事情,那么就会期待非常奇怪的结果。众所周知,C 广泛使用 karma,为那些编写晦涩代码的人带来麻烦。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-10-14
        • 2019-02-14
        • 2012-08-05
        • 1970-01-01
        • 1970-01-01
        • 2017-02-27
        • 1970-01-01
        • 2022-11-01
        相关资源
        最近更新 更多