Можно ли использовать printf как имя переменной?

Правила для имен переменных в C следующие:

  1. Имя переменной может содержать только буквы (как прописные, так и строчные), цифры и символы подчеркивания.
  2. Первая буква переменной должна быть либо буквой, либо знаком подчеркивания.
  3. Не существует правила относительно длины имени переменной (идентификатора). Однако вы можете столкнуться с проблемами в некоторых компиляторах, если имя переменной длиннее 31 символа. (источник: [https://www.programiz.com/c-programming/c-variables-constants])

Мне интересно, теоретически можно ли использовать single underbar(_) или double underbar(__) в качестве переменной? и можно ли использовать printf или scanf в качестве переменной?

Во время игры с компилятором c (Dev C++) и linux Ubuntu Vi, даже если я использовал это имя в качестве имени переменной, ошибок или предупреждений не было.

Код, который я использовал, выглядит следующим образом:

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

person Learner_15    schedule 24.03.2021    source источник


Ответы (5)


да, их можно использовать. видеть:

Код:

~> 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
person Daniel Heinrich    schedule 24.03.2021
comment
Может быть полезно объяснить, почему их можно использовать. Также пример __ не соответствует требованиям. - person Lundin; 24.03.2021

Когда вы инициализируете printf как имя переменной, вы больше не можете использовать команду printf, как это происходит с scanf. Первоначально команда printf указывала на код для ввода, но теперь вы присвоили ему целое число.

person rktejesh    schedule 24.03.2021
comment
вы не можете в том же объеме. - person Antonin GAVREL; 24.03.2021

Вы можете, но это не значит, что вы должны.

Да, _ и __ являются допустимыми идентификаторами в том смысле, что они удовлетворяют правилам для идентификаторов. Они могут привести к тому, что код будет труден для чтения и может столкнуться с именем, уже используемым реализацией, поэтому вам не следует использовать их самостоятельно таким образом.

Что касается использования printf и scanf в качестве имен переменных, вы можете сделать это только в том случае, если вы еще не объявили их как функции - Другими словами, вы не можете сделать это, если вы уже включили stdio.h.

C имеет четыре пространства имен для идентификаторов (или, точнее, четыре класса пространств имен); вы можете использовать один и тот же идентификатор для двух разных вещей в одной и той же области, только если они принадлежат к разным пространствам имен. Пространства имен:

  • Все метки (устраняются неоднозначностью с помощью ключевого слова goto или завершающего ':');
  • Все имена тегов (устраненные ключевыми словами struct, enum или union);
  • Имена членов struct и union (устраняются неоднозначность операторами . или ->; идентификаторы могут использоваться в нескольких типах struct и union)
  • Все остальные имена (имена переменных, имена функций, константы перечисления и т.

Если вы включили stdio.h, то printf и scanf уже были объявлены как имена функций, поэтому вы не можете также использовать их в качестве имен переменных в этой области, поскольку имена функций и имена переменных принадлежат одному и тому же пространству имен. Однако вы можете использовать их в качестве имен тегов, имен элементов или меток, хотя я настоятельно рекомендую вам не делать этого.

person John Bode    schedule 24.03.2021
comment
Что касается «вы можете сделать это только в том случае, если вы еще не объявили их как функции»: идентификаторы во внутренних областях могут скрывать идентификаторы во внешних областях. - person Eric Postpischil; 25.03.2021

Вы можете использовать имена scanf и printf в области действия блока или в пространстве имен тегов структур, объединений или перечислений, или в пространстве имен членов структур и объединений, или в области действия прототипа функции.

Имя типа scanf или printf, объявленное в области блока, скроет соответствующее имя функции, объявленное в области файла. Но вы не можете повторно объявлять эти имена в области файлов.

Вот демонстрационная программа.

#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 __;

Имя зарезервировано реализацией.

Что касается этого объявления в вашем фрагменте кода

 int _;

тогда, поскольку он не имеет файловой области (у него есть блочная область), тогда используемый в объявлении идентификатор (объявление, использующее этот идентификатор) является допустимым.

Но если вы объявите имя в области файлов, например

 int _;

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

то такое объявление идентификатора будет недействительным.

Также вы не можете использовать такой идентификатор в качестве имени тега в области видимости файла. Например

struct _
{
    int x;
};

int main( void )
{
    //...
}

— Все идентификаторы, начинающиеся со знака подчеркивания, всегда зарезервированы для использования в качестве идентификаторов с файловой областью как в обычном пространстве имен, так и в пространстве имен тегов.

person Vlad from Moscow    schedule 24.03.2021

  • #P1#
    #P2#
    #P3#
  • #P4#
    #P5#

и можно ли использовать printf или scanf в качестве переменной?

Теоретически вы можете сделать это в локальной области. 7.1.3 далее говорится:

Каждый идентификатор с областью действия файла, перечисленный в любом из следующих подпунктов (включая будущие указания библиотеки), зарезервирован для использования в качестве имени макроса и в качестве идентификатора с областью действия файла в том же пространстве имен, если включен какой-либо из связанных с ним заголовков.

Это означает, что вы не можете объявить переменную или функцию с именем printf в области файла, но вы можете сделать это в локальной области. Теперь, конечно, люди все время объявляют макросы с именем printf с целью имитации функций, поэтому на практике это безвредно.

Но общее практическое правило таково: если вы делаете действительно странные вещи, ждите действительно странных результатов. Известно, что C широко использует карму, чтобы навлечь неприятности на тех, кто заслуживает этого за написание малопонятного кода.

person Lundin    schedule 24.03.2021