Формальные параметры функции
Если функция имеет аргументы, значит должны быть объявлены переменные, которые примут их значения. Эти переменные называются формальными параметрами функции. Внутри функции они фигурируют как обычные локальные переменные. Как показано в следующем фрагменте программы, они объявляются после имени функции внутри круглых скобок:
/* Возвращает 1, если в строке s содержится символ c, в противном
случае возвращает 0 */
int is_in(char *s, char c)
Функция is_in() имеет два параметра: s и с, она возвращает 1, если символ, записанный в переменной с, входит в строку s, в противном случае она возвращает 0.
Внутри функции формальные параметры ничем не отличаются от обычных локальных переменных, единственное их отличие состоит в том, что при входе в функцию они получают значения аргументов. Можно, например, присваивать параметру какое-либо значение или использовать его в выражении. Необходимо помнить, что, как и локальные переменные, формальнее параметры тоже являются динамическими переменными и, следовательно, разрушаются при выходе из функции.
Глобальные переменные
В отличие от локальных, глобальные переменные видимы и могут использоваться в любом месте программы. Они сохраняют свое значение на протяжении всей работы программы. Чтобы создать глобальную переменную, ее необходимо объявить за пределами функции. Глобальная переменная может быть использована в любом выражении, независимо от того, в каком блоке это выражение используется.
В следующем примере переменная count объявлена вне каких бы то ни было функций. Ее объявление расположено передmain(), однако, оно может находиться в любом месте перед первым использованием этой переменной, но только не внутри функции. Объявлять глобальные переменные рекомендуется в верхней части программы.
int count; /* глобальная переменная count */
printf(«count равно %d», count); /* напечатает 100 */
for(count=1; count<10; count++)
Внимательно посмотрите на эту программу. Обратите внимание на то, что ни в func1(), ни в func2() нет объявления переменной count, однако они обе могут ее использовать. В func2() эта возможность не реализуется, так как в ней объявлена локальная переменная с тем же именем. Когда внутри func2() происходит обращение к переменной count, то это будет обращение к локальной, а не глобальной переменной. Таким образом, выполняется следующее правило: если локальная и глобальная переменные имеют одно и то же имя, то при обращении к ней внутри блока, в котором объявлена локальная переменная, происходит ссылка на локальную переменную, а на глобальную переменную это никак не влияет.
Глобальные переменные хранятся в отдельной фиксированной области памяти, созданной компилятором специально для этого. Глобальные переменные используются в тех случаях, когда разные функции программы используют одни и те же данные. Однако рекомендуется избегать излишнего использования глобальных переменных, потому что они занимают память в течение всего времени выполнения программы, а не только тогда, когда они необходимы. Кроме того, и это еще более важно, использование глобальной переменной делает функцию менее универсальной, потому что в этом случае функция использует нечто, определенное вне ее. К тому же большое количество глобальных переменных легко приводит к ошибкам в программе из-за нежелательных побочных эффектов. При увеличении размера программы серьезной проблемой становится случайное изменение значения переменной где-то в другой части программы, а когда глобальных переменных много, предотвратить это очень трудно.
Стандарт С определяет четыре типа областей видимости идентификаторов:
Тип области видимости
Область видимости
область действия — файл (имя, объявленное вне всех блоков и классов, можно использовать в транслируемом файле, содержащем это объявление; такие имена называются глобальными (global))
Начинается в начале файла (единица трансляции) и кончается в конце файла. Такую область видимости имеют только идентификаторы, объявленные вне функции. Эти идентификаторы видимы в любом месте файла. Переменные с этой областью видимости являются глобальными)
область действия — блок
Начинается открывающейся фигурной скобкой «<" блока и кончается с его закрытием скобкой ">«. Эту область видимости имеют также параметры функции. Переменные, имеющие такую область видимости, являются локальными в своем блоке
область действия — прототип функции
Идентификаторы, объявленные в прототипе функции, видимы внутри прототипа
область действия — функция (имена, объявленные в функции, могут быть использованы только в теле функции)
Начинается открывающейся фигурной скобкой «<" функции и кончается с ее закрытием скобкой ">«. Такую область видимости имеют только метки. Метка используется оператором goto и должна находится внутри той же функции
Спецификатор extern
Прежде чем приступить к рассмотрению спецификатора extern, необходимо коротко остановиться на компоновке программы. В языке С при редактировании связей к переменной может применяться одно из трех связываний: внутреннее, внешнее или же не относящееся ни к одному из этих типов. (В последнем случае редактирование связей к ней не применяется.) В общем случае к именам функций и глобальных переменных применяется внешнее связывание. Это означает, что после компоновки они будут доступны во всех файлах, составляющих программу. К объектам, объявленным со спецификатором static и видимым на уровне файла, применяется внутреннее связывание, после компоновки они будут доступны только внутри файла, в котором они объявлены. К локальным переменным связывание не применяется и поэтому они доступны только внутри своих блоков.
Спецификатор extern указывает на то, что к объекту применяется внешнее связывание, именно поэтому они будут доступны во всей программе. Далее нам понадобятся чрезвычайно важные понятия объявления и описания. Объявление(декларация) объявляет имя и тип объекта. Описание [1] выделяет для объекта участок памяти, где он будет находиться. Один и тот же объект может быть объявлен неоднократно в разных местах, но описан он может быть только один раз.
В большинстве случаев объявление переменной является в то же время и ее описанием. Однако, если перед именем переменной стоит спецификатор extern, то объявление переменной может и не быть ее описанием. Таким образом, если нужно сослаться на переменную, определенную в другой части программы, необходимо объявить ее как внешнюю (extern).
Приведем пример использования спецификатора extern. Обратите внимание, что глобальные переменные first и lastобъявлены после main().
extern int first, last; /* используются глобальные переменные */
printf(«%d %d», first, last);
/* описание глобальных переменных first и last */
int first = 10, last = 20;
Программа напечатает 10 20, потому что глобальные переменные first и last инициализированы этими значениями. Объявление extern сообщает компилятору, что переменные first и last определены в другом месте, поэтому программа компилируется без ошибки, несмотря даже на то, что first и last используются до своего описания.
Обратите внимание, в этом примере объявление переменных со спецификатором extern необходимо только потому, что они не были объявлены до main(). Если бы их объявление встретилось перед main(), то в объявлении со спецификатором externне было бы необходимости.
При компиляции выполняются следующие правила. Если компилятор находит переменную, не объявленную внутри блока, он ищет ее объявление во внешних блоках. Если не находит ее и там, то ищет среди объявлений глобальных переменных. В предыдущем примере, если бы не было объявления extern, компилятор не нашел бы first и last среди глобальных переменных, потому что они объявлены после main(). Здесь спецификатор extern сообщает компилятору, что эти переменные будут объявлены в файле позже.
Как сказано выше, спецификатор extern позволяет объявить переменную, не описывая ее. Но если в объявлении со спецификатором extern инициализировать переменную, то это объявление становится также и описанием. При этом программист обязательно должен учитывать, что объект может иметь много объявлений, но лишь одно описание.
Спецификатор extern играет большую роль в программах, состоящих из многих файлов. В языке С программа может быть записана в нескольких файлах, которые компилируются раздельно, а затем компонуются в одно целое. В этом случае необходимо как-то сообщить всем файлам о глобальных переменных программы. Самый лучший (и наиболее переносимый) способ сделать это — определить (описать) все глобальные переменные в одном файле и объявить их со спецификатором extern в остальных файлах, как показано на рис. 2.1.
Файл 1 Файл 2
int x, y; extern int x, y;
char ch; extern char ch;
int main(void) void func22(void)
void func1(void) void func23(void)
Рис. 2.1. Использование глобальных переменных в раздельно компилируемых модулях
Во втором файле спецификатор extern сообщает компилятору, что эти переменные определены в других файлах. Таким образом компилятор узнает имена и типы переменных, размещенных в другом месте, и может отдельно компилировать второй файл, ничего не зная о первом. При компоновке этих двух модулей все ссылки на глобальные переменные будут разрешены.
На практике программисты обычно включают объявления extern в заголовочные файлы, которые просто подключаются к каждому файлу исходного текста программы. Это более легкий путь, который к тому же приводит к меньшему количеству ошибок, чем повторение этих объявлений вручную в каждом файле.
Спецификатор extern можно применять в объявлении функций, но в этом нет необходимости.
Спецификатор static
Переменные, объявленные со спецификатором static, хранятся постоянно внутри своей функции или файла. В отличие от глобальных переменных они невидимы за пределами своей функции или файла, но они сохраняют свое значение между вызовами. Эта особенность делает их полезными в общих и библиотечных функциях, которые будут использоваться другими программистами. Спецификатор static воздействует на локальные и глобальные переменные по-разному.
Локальные статические переменные
Для локальной переменной, описанной со спецификатором static, компилятор выделяет в постоянное пользование участок памяти, точно так же, как и для глобальных переменных. Коренное отличие статических локальных от глобальных переменных заключается в том, что статические локальные переменные видны только внутри блока, в котором они объявлены. Говоря коротко, статические локальные переменные — это локальные переменные, сохраняющие свое значение между вызовами функции.
Статические локальные переменные очень важны при создании функций, работающих отдельно, так как многие процедуры требуют сохранения некоторых значений между вызовами. Если бы не было статических переменных, вместо них пришлось бы использовать глобальные, подвергая их риску непреднамеренного изменения другими участками программы. Рассмотрим пример функции, в которой особенно уместно применение статической локальной переменной. Это — генератор последовательности чисел, каждое из которых зависит только от предыдущего. Для хранения числа между вызовами можно использовать глобальную переменную. Однако тогда при каждом использовании функции придется объявлять эту переменную и, что особенно неудобно, постоянно следить за тем, чтобы ее объявление не конфликтовало с объявлениями других глобальных переменных. Значительно лучшее решение — объявить эту переменную со спецификатором static:
static int series_num;
В этом примере переменная series_num продолжает существовать между вызовами функций, в то время как обычная локальная переменная создается заново при каждом вызове, а затем уничтожается. Поэтому в данном примере каждый вызовseries() генерирует новое число, зависящее от предыдущего, причем удается обойтись без глобальных переменных.
Статическую локальную переменную можно инициализировать. Это значение присваивается ей только один раз — в начале работы всей программы, но не при каждом входе в блок программы, как обычной локальной переменной. В следующей версии функции series() статическая локальная переменная инициализируется числом 100:
static int series_num = 100;
Теперь эта функция всегда будет генерировать последовательность, начинающуюся с числа 123. Однако во многих случаях необходимо дать пользователю программы возможность ввести первое число вручную. Для этого переменнуюseries_num можно сделать глобальной и предусмотреть возможность задания начального значения. Если же отказаться от объявления переменной series_num в качестве глобальной, то необходимо ее объявить со спецификатором static.
Глобальные статические переменные
Спецификатор static в объявлении глобальной переменной заставляет компилятор создать глобальную переменную, видимую только в том файле, в котором она объявлена. Статическая глобальная переменная, таким образом, подвергается внутреннему связыванию, как описано ранее в разделе «Спецификатор extern». Это значит, что хоть эта переменная и глобальная, тем не менее процедуры в других файлах не увидят ее и не смогут случайно изменить ее значение. Этим снижается риск нежелательных побочных эффектов. А в тех относительно редких случаях, когда для выполнения задачи статическая локальная переменная не подойдет, можно создать небольшой отдельный файл, который содержит только функции, в которых используется эта статическая глобальная переменная. Затем этот файл необходимо откомпилировать отдельно; тогда можно быть уверенным, что побочных эффектов не будет.
В следующем примере иллюстрируется применение статической глобальной переменной. Здесь генератор последовательности чисел переделан так, что начальное число задается вызовом другой функции, series_start():
/* Это должно быть в одном файле
отдельно от всего остального. */
static int series_num;
void series_start(int seed);
/* иницилизирует переменную series_num */
void series_start(int seed)
Вызов функции series_start() с некоторым целым числом в качестве параметра инициализирует генератор series(). После этого можно генерировать последовательность чисел путем многократного вызова series().
Обзор: Имена локальных статических переменных видимы только внутри блока, в котором они объявлены; имена глобальных статических переменных видимы только внутри файла, в котором они объявлены.
Если поместить функции series() и series_num() в библиотеку, то уже нельзя будет сослаться на переменнуюseries_num, она оказалась спрятанной от любых операторов всей остальной программы. При этом в программе (конечно, в других файлах) можно объявить и использовать другую переменную под именем series_num. Иными словами, спецификаторstatic позволяет создать переменную, видимую только для функций, в которых она нужна, что исключает нежелательные побочные эффекты.
Таким образом, при разработке больших и сложных программ для «сокрытия» переменных можно применять спецификаторstatic.
Спецификатор register
Первоначально спецификатор класса памяти register применялся только к переменным типа int, char и для указателей. Однако стандарт С расширил использование спецификатора register, теперь он может применяться к переменным любых типов.
В первых версиях компиляторов С спецификатор register сообщал компилятору, что переменная должна храниться в регистре процессора, а не в оперативной памяти, как все остальные переменные. Это приводит к тому, что операции с переменной register осуществляются намного быстрее, чем с обычными переменными, потому такая переменная уже находится в процессоре и не нужно тратить время на выборку ее значения из оперативной памяти (и на запись в память).
В настоящее время определение спецификатора register существенно расширено. Стандарты С89 и С99 попросту декларируют «доступ к объекту так быстро, как только возможно». Практически при этом символьные и целые переменные по-прежнему размещаются в регистрах процессора. Конечно, большие объекты (например, массивы) не могут поместиться в регистры процессора, однако компилятор получает указание «позаботиться» о быстродействии операций с ними. В зависимости от конкретной реализации компилятора и операционной системы переменные register обрабатываются по-разному. Иногда спецификатор register попросту игнорируется, а переменная обрабатывается как обычная, однако на практике это бывает редко.
Спецификатор register можно применить только к локальным переменным и формальным параметрам функций. В объявлении глобальных переменных применение спецификатора register не допускается. Ниже приведен пример использования переменной, в объявлении которой применен спецификатор register; эта переменная используется в функции возведения целого числа m в степень. (Степень — натуральное число — представлена идентификатором е.)
int int_pwr(register int m, register int e)
register int temp;
for(; e; e—) temp = temp * m;
В этом примере в объявлениях к переменным е, m и temp применен спецификатор register потому, что они используются внутри цикла. Переменные register идеально подходят для оптимизации скорости работы цикла. Как правило, переменныеregister используются там, где от них больше всего пользы, а именно, когда процесс многократно обращается к одной и той же переменной. Это существенно потому, что в объявлении можно применить спецификатор register к любой переменной, но средства оптимизации быстродействия могут быть применены далеко не ко всем переменным в равной степени.
Максимальное количество переменных register, оптимизирующихся по быстродействию, зависит от среды программирования и конкретной реализации компилятора. Если таких переменных окажется слишком много, то компилятор автоматически преобразует регистровые переменные в нерегистровые. Этим обеспечивается переносимость программы в широком диапазоне процессоров.
Обычно в регистры процессора можно поместить как минимум две переменные типа char или int. Однако в различных средах программирования режимы оптимизации могут очень отличаться, поэтому выбор режима оптимизации необходимо осуществлять с учетом особенностей конкретного компилятора.
В языке С с помощью оператора & (рассматривается в этой главе далее) нельзя получить адрес регистровой переменной, потому что она может храниться в регистре процессора, который обычно не имеет адреса.
Хотя в настоящее время применение спецификатора register в значительной мере вышло за его традиционные рамки, практически ощутимый эффект от его применения по-прежнему может быть получен только для переменных целого и символьного типа. Не следует ожидать заметного повышения скорости от объявления регистровыми переменных других типов.
Name already in use
StudentCpp-wiki / 1.1. Переменные.md
- Go to file T
- Go to line L
- Copy path
- Copy permalink
- Open with Desktop
- View raw
- Copy raw contents Copy raw contents
Copy raw contents
Copy raw contents
Переменная — это область память с заданным символьным именем.
В этой строчке в памяти выделяется память для хранения целочисленного числа и в программе к этой области памяти мы сможем обращаться по имени «а».
Суть переменных — хранить данные в памяти и предоставлять быстрый, понятный доступ к этим данным по понятному человеку имени. Самому-то компьютеру имя «а» вообще не нужно, он на самом деле при компляции программы понятное вам имя заменит на понятный ему адрес данных в памяти.
Объявление переменной — процесс резервирования в памяти нужного объема памяти и присвоения этой области памяти какого-то имени.
Резервирование памяти — явление, при котором программа помечает область памяти «занятой», чтобы не произошло непроизвольного изменения данных в этом участке памяти.
Объявить переменную — это только зарезервировать под нее память. Никакого вразумительного значения в этой памяти не хранится. Принято считать, что после обявления переменной в памяти хранится «мусор» — случайное значение, которое было в памяти.
Для объявления переменной сначала пишут имя типа данных будущей переменной, а затем имя этой переменной.
Обратите внимание, что типов данных в языках программирования достаточно много, причем бывают также и пользовательские типы данных, которые программист может создавать сам и по своим потребностям (но это будет рассматриваться позже).
Сначала может показаться, что имя типа данных определеяет только то, сколько памяти будет зарезервировано под переменную. Но это так. Переменные а2 и а3 будут занимать в памяти одно и то же количество байт, но если выполнить следующий код:
Маленькое замечение: в языке С++ логический тип данных ничем не отличается от числового. Все, что отлично от 0 — истина, и только сам 0 — ложь.
Итак, обратите внимание, что на деле переменные а2 и а3 обе в одном байте памяти хранят число 65. Но при выводе на экран, а2 выводится как символ, а а3 как число (более продвинутый язык С# бы вывел как и положено логическому типу данных фразу «true» — истина, но это С++, поэтому сильно не переживайте по этому поводу). Почему?
Все из-за разных типов данных этих переменных.
Тип данных — это некий комментарий программы к зарезервированному участку памяти, чтобы знать, как работать с той или иной информацией.
Объявление и инициализацию можно совмещать
ВАЖНО! Считается обязательным давать переменным вразумительные имена, чтобы только по самому имени переменной было понятно, для чего она создана Например, переменные счетчики называют
Чтобы посчитать что-то, то используют имя
Имеется в виду, что c — сокращение от character — символ. Вообще привыкайте, что знать английский язык нужно на уровне «читать»-«писать» как минимум
Машина не может хранить ничего другого в памяти как набор нулей и единиц, т.е. чисел. Но нам-то с вами было бы неплохо иметь возможность работать не только с нулями и единицами, а с десятичными числами, числами с плавающей запятой, с символами, строками и т.д. Для этого и придумали типы данных.
Помечая каждую переменную определенным типом данных, мы говорим программе, как мы хотим работать с той или иной информацией.
Переменную а2 мы пометили символьным типом данных — заведомо сказали программе, что мы будем работать с информацией как с символами. Поэтому и при выводе на экран программа увидела эту «пометку» к переменной и вывела символ, а не число.
Инициализация переменной — процесс записи в область памяти какого-то значения.
Объявление переменной и инициализацию можно объядинать в одном выражении:
Локальные и глобальные переменные
Если кто-то изучал раньше Паскаль, то, возможно, поймет меня. Лично меня страшно бесило, что все переменные в этом языке нужно было объявлять в начале процедуры.
Каждый раз, когда ты понимаешь, что нужна еще одна переменная, нужно скроллить вверх, находить объявление переменных, добавлять туда переменную, возвращаться обратно и продолжать работу. И это притом, что процедура не всегда влезает в один экран! В общем, кошмар.
В С++ такого нет. Переменная может быть объявлена в любом месте программы. Причем считается правильным объявлять переменную как можно ближе к месту, где она будет использована.
Однако, согласитесь может возникнуть премерзкая ситуация:
Понятно, что этот алгоритм можно легко переписать правильно, и тогда двойного объявления переменной b можно избежать, но мне важно проиллюстрировать то, о чем сейчас пойдет речь.
У нас сейчас в одном алгоритме получилось, что объявлено 2 переменных с одним и тем же именем — b. Вроде бы, должна быть ошибка, потому что возникает неоднозначность, какая переменная b, где используется.
Логически мы понимаем, что в двух разных блоках кода — две разные переменные b. И это правильно. Чтобы избежать таких конфликтов в С++ тоже есть понятия, которые позволяют избежать таких неоднозначностей: локальная переменные и глобальные переменные.
Внутри ф-ции мы не объявляли переменную count. Но она все равно доступна, и мы увеличиваем ее значение
В начале программы обнуляем значение переменной. То же самое — внутри main не было объявления переменной, но доступ к ней мы имеем
Если кратко:
- Глобальные переменные хранятся на протяжение выполнения всей программы. Т.е. занимают под себя место.
- Имя глобальной переменной занято. Создание локальной переменной в таким же именем затруднит чтение кода.
- Алгоритм программы становится менее прозрачным, потому что вам нужно знать про все глобальные переменные, какие есть в коде.
Если очень кратко: ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ — ПЛОХО! НЕ ИСПОЛЬЗУЙТЕ ИХ.
Если хотите более развернутого ответа, то можете погуглить. Например, http://www.gunsmoker.ru/2011/04/blog-post.html
Глобальные переменные доступны из любого места в модуле программы. (Т.к. с понятием модуля в языке С++ кто-то может быть пока что не знаком, считайте, что это тот файл, в котором вы пишете код, например, main.cpp)
Глобальные переменные в С++ объявляются вне всех функций. Например, в самом начале программы. И работать с такой переменной можно в любом месте программы, не взирая на границы блоков кода.
Блок кода — код расположенный между символами ‘<' и '>‘
Тогда возникает разумный вопрос: если глобальные переменные такие удобные, почему нельзя везде и всюду использовать именно их?
Дело в том, что в памяти программы глобальные переменные занимают свое особое пространство. И не всегда вы можете быть уверены, что это пространство безгранично. Но даже не это страшно в бездумном использовании глобальных переменных.
Самое плохое — это снижение читаемости и понятности кода. Когда вы используете глобальную переменную в программах сложнее «Hello, World!» вам становится сложно сказать, где и в какой момент меняется состояние этой переменной. Вы не контролируете уровни доступа до нее. Вы можете забыть, где меняется эта переменная, а потом долга искать, почему данные в памяти имеют такой странный вид. Все это сделало использование глобальных переменных нежелательным.
Глобальные переменные такой же инструмент языка программирования, как и многие другие. Нужно уметь применять это с умом! Но всегда, когда возможно обойтись без использования шлобальных переменных, не используйте их.
Глобальные переменные плохи по двум причинам:
Они хранятся в памяти на протяжение всей программы и если глобальные переменные занимаются большой объем памяти (например, статические массивы или большие объекты), это увеличивает занимаемый программой объем оперативной памяти.
Снижение читабельности кода программы
По правилам хорошего тона нужно избегать использовать глобальные переменные, кроме случаев, где по архитектуре программы без этого не обойтись
В отличии от глобальных переменных локальные существуют только в рамках того блока кода, в котором они были объявлены.
Переменная c объявлена в фун-ции Func, поэтому существует только в рамках этой функции. Внутри функции main ее не существует, поэтому при попытке любого к ней обращения будет выдаваться ошибка.
Переменная а объявлена в фун-ции main и существует как в самой функции main, так и во всех дочерних блоках кода любой вложенности. Поэтому переменная а видна в любом месте функции main, в том числе внутри цикла for.
Переменные b и i (!) объявлены внутри цикла for. И да, переменная i является локальной переменной цикла for! Обе этих пермеенные существуют только в рамках цикла и после его завершения уже не существуют.
Разница между переменными i и b заключается в том, что переменная i создается один раз в начале цикла и существует на протяжение всех итераций этого цикла. В то время, как переменная b создается каждый раз на каждой итерации.
Поэтому на протяжение цикла, переменная i будет выводиться на экран как 0, 1, 2, 3, . 9, а переменная b все время будет выводиться на экран равное 2.
Где хранятся локальные переменные
Еще важно помнить, что локальные переменные создаются в стеке программы. И стек ограничен в своем размере.
Архитектурно такое решение оправдано тем, что в стек легко добавлять переменные при их создании с помощью команды push и достаточно помнить, сколько переменных было создано в каждом блоке кода. Тогда доатсточно сделать нужно количество команд pop по завершении блока кода, и стек всегда будет чистым и опрятным, без мусора.
К тому же стек хранит все данные подряд в отличие от «кучи» — динамической памяти программы (о ней будет рассказываться в дальнейшем), а это позволяет исключить дефрагментацию памяти, а соотвественно более высокое быстродейтсвие при работе с этой памятью.
Типы данных в любом языке программирования делятся на 2 вида:
- базовые (встроенные) могут быть использованы «из коробки», они доступны стандартными средствами языка программирования
- пользовательские создаются самим программистом под какие-то свои индивидуальные задачи
Пользовательские типы данных будут рассмотрены в темах «Структуры» и «Классы». Сейчас рассмотрим перечень основных базовых типов данных:
Логический тип данных bool
Хранит всего 2 значения: истина ( true ) или ложь ( false ). Но естественно не смотря на это занимает в памяти полноценный байт памяти по правилу «наименьшая адресуемая ячейка памяти = 1 байту».
Причем в языке С++ истоной является все, что отлично от 0 (нуля), а ложью будет только значение равное нулю. Например,
- 10 — это true
- -1 — это true
- 1 — это true
- 0 — это false
Причем, в С++ работает даже такой код:
Но все же правильнее с логическим типом данных работать именно с константами true и false . Это правильнее, логичнее и не будет вам стоить вредной привычки в дальнейшем. Например, в языке C# логической переменной уже нельзя присваивать числовую константу, только логическую.
Символьный тип данных char
Переменная типа данных char будет хранить символ и занимать в памяти 1 байт памяти. Соответственно, char переменная изменяется в диапазоне от 0 до 255. Причем это число является кодом символа из таблицы ASCII (Полный перечень кодов таблицы ASCII).
Тип данных char дает программе понять, что при выводе такой переменной на экран нужно выводить не число, а символ с таким кодом.
Целочисленные типы данных
В С++ есть несколько целочисленных типов данных. Все они различаются только размером и как следствие диапазоном своих изменяемых значений. Причем целочисленный тип данных может быть знаковым — изменяться в диапазоне от отрицательного до положительного числа или беззнаковым — не иметь отрицательного диапазона чисел.
- short занимает 2 байта
- int занимает 4 байта
- long занимает 8 байт
Как можно легко вычислить диапазон чисел, который может хранить целочисленный тип данных. Возьмем для примера short :
2 байта — 16 бит, т.е. 16 разрядов. Максимальное число, которое может храниться в двоичном представлении это:
или это число еще можно записать как:
А это число легко можно записать уже на «человеческом языке» как
2 в степени 16 (потому что единица стоит в 16-ом разряде) минус единица. Возьмите калькулятор и посчитайте (или если вы крутой, то посчитайте в уме), какое получается число.
Итак, это число 65535 . Таким образом диапазон типа данных short изменяет от 0 до 65535. Но на самом деле так изменяется unsigned short — беззнаковый вариант этого типа данных.
Сам же short изменяется в диапазоне от -32768 до 32767 — беззнаковый диапазон поделился по сути пополам.
Теперь вы можете легко высчитывать диапазон изменения целочисленных переменных в зависимости от типа данных.
Кстати, маленькое замечание: short , int , long — это всего лишь псевдонимы типов данных. И эти псевдонимы могут на разных платформах и архитектурах скрывать различные типы данных с разными размерами. На самом деле, при написании кросс-платформенных приложений лучше пользоваться системными названиями __int16 , __int32 , __int64 и т.д. Но когда это не жизненно важно, то обычно пользуются именами-псевдонимами.
Типы данных с плавающей запятой
Типы с плавающей запятой также различаются по размеру. Но в силу особенностей хранения чисел с плавающей запятой говорят, что они отличаются не диапазоном, а точностью — кол-вом знаков после запятой, которые они могут хранить.
6.4 – Введение в глобальные переменные
В уроке «6.3 – Локальные переменные» мы рассмотрели, что локальные переменные – это переменные, определенные внутри функции (или параметры функции). Локальные переменные имеют область видимости блока (видны только внутри блока, в котором они объявлены) и имеют автоматическую продолжительность (они создаются в точке определения и уничтожаются при выходе из блока).
В C++ переменные также могут быть объявлены вне функции. Такие переменные называются глобальными переменными.
Объявление и именование глобальных переменных
По соглашению глобальные переменные объявляются в верхней части файла, ниже включений заголовочных файлов, но выше любого кода. Ниже показан пример определения глобальной переменной:
Приведенный выше пример напечатает:
По соглашению многие разработчики добавляют к идентификаторам глобальных переменных префикс " g " или " g_ ", чтобы указать, что они глобальные.
Лучшая практика
Рассмотрите возможность использования префикса " g " или " g_ " для глобальных переменных, чтобы помочь отличить их от локальных переменных.
Глобальные переменные имеют область видимости файла и статическую продолжительность
Глобальные переменные имеют область видимости файла (также неофициально называемую глобальной областью видимости или областью видимости глобального пространства имен), что означает, что они видны с момента объявления до конца файла, в котором они объявлены. С момента объявления глобальную переменную можно использовать в любом месте файла! В приведенном выше примере глобальная переменная g_x используется в обеих функциях doSomething() и main() .
Поскольку они определяются вне функции, глобальные переменные считаются частью глобального пространства имен (отсюда и термин «область видимости глобального пространства имен»).
Глобальные переменные создаются при запуске программы и уничтожаются при ее завершении. Это называется статической продолжительностью. Переменные со статической продолжительностью иногда называют статическими переменными.
В отличие от локальных переменных, которые по умолчанию не инициализируются, статические переменные по умолчанию инициализируются нулем.
Инициализация глобальной переменной
При желании неконстантные глобальные переменные можно инициализировать:
Константные глобальные переменные
Как и локальные переменные, глобальные переменные могут быть константными. Как и все константы, константные глобальные переменные должны быть инициализированы.
Связанный контент
Предупреждение о (неконстантных) глобальных переменных
У начинающих программистов часто возникает соблазн использовать множество глобальных переменных, потому что их можно использовать без явной передачи их каждой функции, которая в них нуждается. Однако следует вообще избегать использования неконстантных глобальных переменных! А почему, мы обсудим в следующем уроке «6.9 – Почему глобальные переменные – это зло».
Где хранить глобальные переменные?
Где, с точки зрения грамотной архитектуры, хранить глобальные переменные?
Ради большей чёткости вопроса, опишу остальные условия задачи, хотя многие наверное по умолчанию бы их подразумевали. Остальные условия такие:
* в первую очередь, интересует специфика web-приложений построенных согласно MVC-архитектуре.
Пример кода на PHP:
Будет ли такой вариант хорошим?
Может есть способ проще и изящней?
Может можно вовсе обойтись без глобальных переменных?
Прошу делиться опытом.
- Вопрос задан более трёх лет назад
- 9042 просмотра
- Вконтакте
«Может можно вовсе обойтись без глобальных переменных?» — этот вопрос надо задавать себе лично.
А так, у тебя есть главная модель, которая хранит какое либо свойство. В свою очередь каждая вьюха и главный контроллер имеют ссылку на данную модель, тем самым имеют и доступ к нужному свойству модели.
- Вконтакте

- Вконтакте
Экземпляры классов тоже переменные. Если они не вложены в другие экземпляры классов, то они находятся в глобальном пространстве имён. Можно конечно эти объекты искусственно спрятать в статик-классы/функции, но это будет лишь дым и зеркала не меняющие положения вещей.
Получается, какие-то экземпляры классов высшей абстракции всё равно будут в глобальном пространстве имён (

Согласен, но экземпляр этого супер-класса будет глобальной переменной. К тому же это порочная практика, по сути это передислокация поля глобальных переменных в корень этого дерева.
В чём смысл правила — не создавать глобальные переменные? Чтобы минимизировать количество связей между частями кода. Есть нераспутываемый комок связей, мы оборачиваем его в один класс, и наружу торчит одна переменная, но проблему это не решает. Сложность системы не снизилась, хотя формально правило соблюдено. В этом и сложность. Можно поэкспериментировать, но реально почувствовать верность или неверность выбранного подхода можно будет только хорошо поработав над проектом.

Ну, одно из преимуществ такого подхода — наличие контроля над этими переменными, теперь членами класса.
А какую проблему это не решает? Комка связей? Здесь, мне кажется, нужно именно убирать переменные, прямо не относящиеся к этому (корневому) классу туда, где им место. Ну, например, нужно ввести константу — размер буфера для чтения из сокета. Она как-бы глобальная и «удобно» настраивать все «на самом верху», но по сути константа относится непосредственно к сокету и должна принадлежать именно классу сокета (static естественно). В этом моя основная мысль организации архитектуры классов. Таким образом все, казалось бы глобальные, переменные/константы/настройки разбредутся по своим классам и в корневом останется только то, что относится к «сайту».