Как объявить глобальную переменную?

Тема в разделе "WASM.BEGINNERS", создана пользователем intel_x128, 7 июн 2009.

  1. Ustus

    Ustus New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2005
    Сообщения:
    834
    Адрес:
    Харьков
    Booster
    Придираешься? :):):)
    Да заметил я, заметил... А что поделаешь? Кто сказал, что запрет редактирования - благо? :lol: :lol: :lol:

    Не лучше, уж поверь. Потому что в таком случае никто не мешает написать так:

    m1.cpp:
    Код (Text):
    1. #include <iostream>
    2.  
    3. int a = 256;
    4.  
    5. void print_a()
    6. {
    7.     std::cout << "a = " << a << std::endl;
    8. }
    m2.cpp:
    Код (Text):
    1. extern char a;
    2. void print_a();
    3.  
    4. int main()
    5. {
    6.     print_a();
    7.     a = 1;
    8.     print_a();
    9.     return 0;
    10. }
    И что получим на выходе? Я не выдумал, я примерно такой код видел у наших горе-кодеров. При подходе по второму варианту такие глюки исключены.

    cppasm
    Меня таки проглючило, в си тоже внешнее связывание, там другое отличие - там extern подразумевается. То есть можно написать так:
    m1.cpp:
    Код (Text):
    1. int a = 1;
    m2.cpp:
    Код (Text):
    1. int a;
    2.  
    3. void f()
    4. {
    5.     printf("a = %d\n", a);
    6.     /* на выходе 1, как ни странно. */
    7. }
    и это работает, как ни странно! Только не спрашивайте меня как. Видимо Страуструп тоже напугался таких конструкций и в плюс-плюсе такие гуси уже не летают.
     
  2. Ustus

    Ustus New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2005
    Сообщения:
    834
    Адрес:
    Харьков
    cppasm
    тьфу ты... во втором примере предыдущего поста имена файлов, разумеется m1.c и m2.c (а то тут, знаете ли, иногда придираются :) )
     
  3. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Ustus
    Я поверю во что угодно, но что мешает так написать во втором варианте? И при чём здесь вообще криминал? Говнокод он и африке говнокод, его всегда можно написать.

    Код (Text):
    1. То есть можно написать так:
    Шутить не надо. Но что можно ожидать от неинициализированной переменной? Что она будет каким-то магическим числом?
     
  4. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    С какого вдруг перепугу? Для чего его вообще тогда ввели в Си?
     
  5. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    ...* детектед!
    потому что чушь несете)
     
  6. Ustus

    Ustus New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2005
    Сообщения:
    834
    Адрес:
    Харьков
    Booster
    Во втором варианте в обоих единицах компиляции тип переменной согласуется благодаря подключению общего хедера.

    В том-то и дело, что это не будет неинициализированная переменная, это будет тоже самое, что и extern int a; А вот если ее инициализировать - вылетит ошибка линкера - дублирование символа. Я же говорю - очень мутно это в си можно сделать. Но, конечно, не нужно.

    Great
    Да ладно... а то с вами не бывает... :)
     
  7. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Да откуда это взялось? Мне что просто поверить на слово и отбросить свои прежние знания?
    Хорошо, а как тогда сделать не extern объявление?
     
  8. AsmGuru62

    AsmGuru62 Member

    Публикаций:
    0
    Регистрация:
    12 сен 2002
    Сообщения:
    689
    Адрес:
    Toronto
    Существует тенденция "боязни" глобальных переменных. То же и с "goto".
    Всё это догмы. Далее приведен пример как можно сделать глобальные переменные.

    Прежде всего: единство места. Все переменные - в одном месте (и без шуток, пожалуйста).
    Это значит нам нужна структура, например такая:
    Код (Text):
    1. typedef struct
    2. {
    3.     int Variable1;
    4.     char Variable2 [80];
    5.     char* Variable3;
    6.     //
    7.     // etc.
    8.     //
    9. }
    10. GLOBALS;
    Понятно, что во всех модулях (файлах), кроме одного, должна быть такая декларация:
    Код (Text):
    1. extern GLOBALS glb;
    И в одном единственном модуле должно быть следующее:
    Код (Text):
    1. GLOBALS glb;
    Естественно, расписывать всё это для каждого модуля это конечно маразм.
    Поэтому необходим .Н файл:
    Код (Text):
    1. // --------------------------------------------
    2. // FILE: GLOBALS.H
    3. // --------------------------------------------
    4. // New variables to be added here
    5. // --------------------------------------------
    6. typedef struct
    7. {
    8.     int Variable1;
    9.     char Variable2 [80];
    10.     char* Variable3;
    11.     //
    12.     // etc.
    13.     //
    14. }
    15. GLOBALS;
    16.  
    17. // --------------------------------------------
    18. #ifdef DECLARE_GLOBALS
    19.     GLOBALS glb;
    20. #else
    21.     extern GLOBALS glb;
    22. #endif
    Далее, в одном из модулей (там где "main" функция) включаем GLOBALS.H, но перед этим определим DECLARE_GLOBALS:
    Код (Text):
    1. ...
    2. #define DECLARE_GLOBALS
    3. #include "GLOBALS.H"
    4. ...
    5. int main ()
    6. {
    7.     return 0;
    8. }
    Ну а во всех остальных модулях - просто:
    Код (Text):
    1. #include "GLOBALS.H"
    Самое полезное, что при печатании "glb." Intelli-Sense предоставит список переменных!
     
  9. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    AsmGuru62 Ustus-у расскажи это. А вообще глобальные переменные действительно могут быть полезны, например для оптимизации вызовов функций.
     
  10. Ustus

    Ustus New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2005
    Сообщения:
    834
    Адрес:
    Харьков
    Booster
    А я знаю??? Приползло откуда-то. Вопрос к K&R. Я сам в шоке. Да так все равно не один нормальный человек писать не будет, но сам факт имеет место быть.

    Ну как - обычно, static.

    Что именно? Что не надо бояться глобальных переменных? Да я и не боюсь. Просто обычно - не всегда, но обычно - глобальные переменные - признак недостаточного понимания структуры. Кстати, с goto тоже самое :):):)

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

    AsmGuru62
    Нормально, только если приложение логически одномодульное. Иначе будет мясо. Как сказал Керниган "C - инструмент острый, как бритва. С его помощью можно создать элегантную программу или кровавое месиво". :):):) Уж поверьте человеку, которому пришлось ковыряться в проекте в несколько десятков тысяч строк, причем все глобальные переменные общие - это адище кромешное, чреватое глюками и ошибками. Причем ошибки такого рода ловить особо противно, потому что они совершенно не локализуются. Любой же рефакторинг превращается в детектив. Так что нафиг, нафиг.
     
  11. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Ustus
    Ты оказался прав. Я не знал этой фичи. Оказывается int foo может быть как декларацией с определением, так и только декларацией.
     
  12. cppasm

    cppasm New Member

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    923
    И в чём это противоречит тому что я написал?
    В C++ разница между extern и extern "C" только в том, что второй варинт заставляет компилятор не манглить имена.
    Я же не говорю что extern вообще не нужен.
     
  13. Ustus

    Ustus New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2005
    Сообщения:
    834
    Адрес:
    Харьков
    Booster
    Мне вот интересно, как это согласуется с парадигмой раздельной компиляции... или в си она не такая раздельная, как в плюсах :):):)

    cppasm
    А здесь может быть по-разному :)
    Если так:
    Код (Text):
    1. extern "C" int x;
    То таки да, это объявление с указанием на то, что манглить имена не надо.
    А если так:
    Код (Text):
    1. extern "C"
    2. {
    3. int x;
    4. }
    То это полноценное определение, опять же с указанием, что следует использовать си-имя. Чтобы это стало объявлением extern придется написать еще раз:
    Код (Text):
    1. extern "C"
    2. {
    3. extern int x;
    4. }
    Вот такая вот паранойя. :)
     
  14. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Ustus
    Похоже, что согласуется нормально. Тем более что компиляция здесь и не причём, а чисто шаманства линкёра. Стиль Cи(аналогия с полями структур). Я ещё посмотрел как с этим обстоит дело в gcc и в cl(7.1). gcc нормально, но cl просто анекдот. extern int foo; с определением int foo; в другом файле, вообще не линкуется. ^)