Форум программистов, компьютерный форум CyberForum.ru

Класс памяти по умолчанию для глобальной переменной - C++

Восстановить пароль Регистрация
 
mcoffka
 Аватар для mcoffka
1 / 1 / 1
Регистрация: 19.03.2014
Сообщений: 10
19.03.2014, 23:16     Класс памяти по умолчанию для глобальной переменной #1
Здравствуйте!
Прочитала такую вещь тут

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

1. Переменная объявлена с классом памяти static. Такая переменная может быть инициализирована явно константным выражением, или по умолчанию нулевым значением. То есть обявления static int i=0 и static int i эквивалентны, и в обоих случаях переменной i будет присвоено значение 0.

2. Переменная объявлена без указания класса памяти, но с явной инициализацией. Такой переменной по умолчанию присваивается класс памяти static. То есть объявления int i=1 и static int i=1 будут эквивалентны.

Переменная объявленная глобально видима в пределах остатка исходного файла, в котором она определена. Выше своего описания и в других исходных файлах эта переменная невидима (если только она не объявлена с классом extern).
Вот что-то не укладывается мне в голове пункт 2 и следующий после него абзац, а точнее то, что написано в скобках.
Как я понимала до прочтения данной информации, глобальная static переменная не будет видна никаким другим файлам программы и даже extern не поможет ее увидеть. Разве не так?
Но если
объявления int i=1 и static int i=1 будут эквивалентны
то почему я могу получить доступ к переменной int i=1 из другого файла с помощью extern, а к static int i=1 не могу?
Поясните, пожалуйста, что я упускаю. Спасибо.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
DrOffset
6427 / 3801 / 881
Регистрация: 30.01.2014
Сообщений: 6,601
20.03.2014, 01:08     Класс памяти по умолчанию для глобальной переменной #2
mcoffka, у вас дока для Си. В С++ немного другие правила (и все немного сложнее). Ну да ладно
Такой переменной по умолчанию присваивается класс памяти static. То есть объявления int i=1 и static int i=1 будут эквивалентны.
Ну это не правда Вот цитата из стандарта С:
6.2.2/5
If the declaration of an identifier for an object has file scope and no storage-class specifier,
its linkage is external.
то есть, если мы явно не указали static, то переменная будет иметь внешнее связывание. А значит такой пример будет корректен:
C
1
2
3
4
5
6
7
8
9
10
// file1.c
int a = 2;
 
// file2.c
int a; 
 
int main()
{
    printf("%d", a); // выводит 2
}
Тогда как для static написано следующее:
6.2.2/3
If the declaration of a file scope identifier for an object or a function contains the storage-
class specifier static, the identifier has internal linkage
То есть, если переменная (или функция) определяется как static, то она имеет внутреннее связывание. Следовательно не может быть доступна через extern в другой единице трансляции. В то время как extern примененный в этой же единице трансляции будет определять то связывание, которое было задано первоначально.
C
1
2
3
4
5
6
7
8
9
10
11
12
13
// file1.c
static int a = 1;
static int b; // тут 0
int c = 2;
 
extern int a; //можно, но а все еще static
 
//file2.c
 
extern int a; //можно, но линкер будет искать переменную "а" с внешним связыванием
              //если такой нет, то при попытке адресовать ее - будет ошибка линковки.
 
extern int c; // все нормально, найдем переменную "с" в file1
Вот пункт про extern, в котором описано то, что я изложил выше:
6.2.2/4
For an identifier declared with the storage-class specifier extern in a scope in which a
prior declaration of that identifier is visible
, if the prior declaration specifies internal or
external linkage, the linkage of the identifier at the later declaration is the same as the
linkage specified at the prior declaration
. If no prior declaration is visible, or if the prior
declaration specifies no linkage, then the identifier has external linkage.
Так что ничего вы не упускаете. Разве что источник информации не совсем корректный выбрали
Tulosba
:)
Эксперт С++
4378 / 3221 / 297
Регистрация: 19.02.2013
Сообщений: 9,044
20.03.2014, 10:56     Класс памяти по умолчанию для глобальной переменной #3
Цитата Сообщение от DrOffset Посмотреть сообщение
C
1
extern int a; //можно, но а все еще static
Хотелось бы пояснений на этот счет. Что это дает?
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16825 / 5246 / 321
Регистрация: 30.03.2009
Сообщений: 14,127
Записей в блоге: 26
20.03.2014, 11:46     Класс памяти по умолчанию для глобальной переменной #4
2. Переменная объявлена без указания класса памяти, но с явной инициализацией. Такой переменной по умолчанию присваивается класс памяти static. То есть объявления int i=1 и static int i=1 будут эквивалентны.
Это заведомое враньё. Я бы НЕ рекомендовал читать статьи, афторы которых не разбираются в том, что пишут

Добавлено через 6 минут
Цитата Сообщение от Tulosba Посмотреть сообщение
Хотелось бы пояснений на этот счет. Что это дает?
Говорит о том, что где-то есть переменная с именем "a" и типом "int". "Где-то" может быть в том числе и в текущем модуле. Если определение глобальной переменной "a" (неважно, static или нет) уже присутствует в текущем модуле, то можно считать, что конструкция "extern int a" игнорируется. Если в текущем модуле глобальной переменной "a" нет, значит она обязательно должна быть в другом модуле и обязательно НЕ-static

Единственный полезный смысл описания extern для переменной, которая определена в текущем модуле - это возможность обращаться к переменной до того, как описано её определение. Типа:

C
extern int a;
...
int *p = &a;
...
int a = 10;
Tulosba
:)
Эксперт С++
4378 / 3221 / 297
Регистрация: 19.02.2013
Сообщений: 9,044
20.03.2014, 11:57     Класс памяти по умолчанию для глобальной переменной #5
Цитата Сообщение от Evg Посмотреть сообщение
Если определение глобальной переменной "a" (неважно, static или нет) уже присутствует в текущем модуле, то можно считать, что конструкция "extern int a" игнорируется
Вот это и хотелось понять. Именно описанный случай.
DrOffset
6427 / 3801 / 881
Регистрация: 30.01.2014
Сообщений: 6,601
20.03.2014, 19:19     Класс памяти по умолчанию для глобальной переменной #6
Tulosba,
Пояснения к параграфу 6.2.2
The appearance of the keyword extern in a declaration, regardless of whether it is
used inside or outside of the scope of a function, indicates a pure reference (ref),
which does not define storage. Somewhere in all of the translation units, at least
one definition (def) of the object must exist. An external definition is indicated
by an object declaration in file scope containing no storage class indication.
Цитата Сообщение от Tulosba Посмотреть сообщение
Вот это и хотелось понять. Именно описанный случай.
Полезное использование может заключаться в более явном определении, что используется именно "внешняя" по отношению к функции переменная:
C
1
2
3
4
5
6
7
8
9
10
static int c;
 
...
 
void funA (void) 
{
    extern int c;  
 
    с = 2;
}
Кстати, если написать наоборот, то получим UB:
C
1
2
extern int a;
static int a;
GCC выдает диагностику, но какой-то другой компилятор может и не выдать и будет прав. По стандарту - UB в случае, если идентификатор имеет одновременно внешнее и внутреннее связывание (6.2.2/7).
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16825 / 5246 / 321
Регистрация: 30.03.2009
Сообщений: 14,127
Записей в блоге: 26
20.03.2014, 19:21     Класс памяти по умолчанию для глобальной переменной #7
Цитата Сообщение от DrOffset Посмотреть сообщение
Полезное использование может заключаться в более явном определении, что используется именно "внешняя" по отношению к функции переменная
Тут немного не то, поскольку static и extern описывают разные объекты
DrOffset
6427 / 3801 / 881
Регистрация: 30.01.2014
Сообщений: 6,601
20.03.2014, 19:39     Класс памяти по умолчанию для глобальной переменной #8
Цитата Сообщение от Evg Посмотреть сообщение
Тут немного не то, поскольку static и extern описывают разные объекты
Нет, это один и тот же объект.
Разъяснения и примеры есть по приведенной мной выше ссылке.
Вот еще один пример:
C
1
2
3
4
5
6
7
static int e = 2;
 
void f()
{
    extern int e;
    printf("e: %d\n", e); // выведет 2
}
Ибо(6.2.2/4):
...which a prior declaration of that identifier is visible, if the prior declaration specifies internal or
external linkage, the linkage of the identifier at the later declaration is the same as the
linkage specified at the prior declaration.
Tulosba
:)
Эксперт С++
4378 / 3221 / 297
Регистрация: 19.02.2013
Сообщений: 9,044
20.03.2014, 20:56     Класс памяти по умолчанию для глобальной переменной #9
Цитата Сообщение от DrOffset Посмотреть сообщение
C++
1
2
3
4
5
6
static int e = 2; 
void f() 
{ 
   extern int e; 
   printf("e: %d\n", e); // выведет 2 
}
а если в другом файле будет глобальная int e; можно к ней получить доступ из файла, где существует static int e; ?
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16825 / 5246 / 321
Регистрация: 30.03.2009
Сообщений: 14,127
Записей в блоге: 26
20.03.2014, 21:34     Класс памяти по умолчанию для глобальной переменной #10
Цитата Сообщение от DrOffset Посмотреть сообщение
Нет, это один и тот же объект
Ты писал про "полезное использование", а потому я и подумал о том, о чём позже задал вопрос Tulosba. Что-то я глюкнул: мне казалось, что вложенный extern спровоцирует использование внешней переменной. Видимо, что-то с чем-то перепутал.

В этом случае я не понимаю, в чём полезность того примера

Цитата Сообщение от Tulosba Посмотреть сообщение
а если в другом файле будет глобальная int e; можно к ней получить доступ из файла, где существует static int e; ?
При таком раскладе получается, что нет. Хотя мне всегда казалось, что сие сделать возможно - бинарные форматы файлов этому не противоречат
DrOffset
6427 / 3801 / 881
Регистрация: 30.01.2014
Сообщений: 6,601
20.03.2014, 21:51     Класс памяти по умолчанию для глобальной переменной #11
Цитата Сообщение от Tulosba Посмотреть сообщение
а если в другом файле будет глобальная int e; можно к ней получить доступ из файла, где существует static int e; ?
Нельзя. В одной единице трансляции не может быть идентификаторов с разным связыванием. Про это я уже писал. Даже если компилятор пропустит - это UB.

Добавлено через 3 минуты
Цитата Сообщение от Evg Посмотреть сообщение
В этом случае я не понимаю, в чём полезность того примера
В декларативности. Мы явно обозначили, что используем внешний по отношению к функции идентификатор, в данном случае глобальный.
На самом деле, если внимательно почитать тот документ, который я приводил, то станет понятно, что подобная возможность - это побочный эффект существующего синтаксиса, который не было смысла запрещать, т.к. он безвреден.
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16825 / 5246 / 321
Регистрация: 30.03.2009
Сообщений: 14,127
Записей в блоге: 26
20.03.2014, 22:18     Класс памяти по умолчанию для глобальной переменной #12
Цитата Сообщение от DrOffset Посмотреть сообщение
В декларативности. Мы явно обозначили, что используем внешний по отношению к функции идентификатор, в данном случае глобальный
Имеется в виду, что явно обозначаем, что используем глобал, а не локал? Тогда это сложно назвать полезностью
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
20.03.2014, 22:29     Класс памяти по умолчанию для глобальной переменной
Еще ссылки по теме:

C++ как сделать матрицу глобальной переменной?
Задать значения глобальной переменной при разных условиях C++
Без глобальной переменной. Уникальные символы из строки на экран copy_if C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
DrOffset
6427 / 3801 / 881
Регистрация: 30.01.2014
Сообщений: 6,601
20.03.2014, 22:29     Класс памяти по умолчанию для глобальной переменной #13
Цитата Сообщение от Evg Посмотреть сообщение
Тогда это сложно назвать полезностью
Это все субъективно. Поэтому я и написал "можно назвать", как бы подчеркивая, что всегда найдется что возразить. Поэтому предлагаю оставить это в стороне.
Действительно полезного примера мы не найдем, потому что эта возможность вывелась сама из существующего синтаксиса. Это как шаблоны в С++ в свое время совершенно неожиданно оказались полны по Тьюрингу и позволили писать метапрограммы. И что мы видим? Споры по поводу нужно это или нет не утихают до сих пор. И это вполне нормально.
Yandex
Объявления
20.03.2014, 22:29     Класс памяти по умолчанию для глобальной переменной
Ответ Создать тему
Опции темы

Текущее время: 21:32. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru