2010-04-09 5 views
16

Я читал, что статические переменные используются внутри функции, когда вы не хотите, чтобы значение переменной изменялось/инициализировалось каждый раз при вызове функции. Но как насчет определения переменной static в основной программе до «main», например.Static, define и const в C

#include <stdio.h> 

static double m = 30000; 

int main(void) 
{ 
value = m * 2 + 3; 
} 

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

const double m = 30000; 

или

#define m 30000 //m or M 

, а затем убедившись, что здесь, чтобы использовать двойные операции в основном коде так чтобы преобразовать m в нужный тип данных.

+0

Спасибо всем за интересные ответы. Поэтому я считаю, что в моем случае лучше всего иметь статический const double = 30000. – yCalleecharan

ответ

12
static double m = 30000; 

double foo(double x, double y) { 
    return x/m + y; 
} 

Это ничего не выиграет. Для вычисления нужно сделать копию m. Кроме того, если вы:

double bar(double x, double y) { 
    m += x + y; 
    return m; 
} 

Тогда все вызовы бар изменится м. Статические переменные за пределами функций (или классов) - это действительно глобальные переменные с областью файлов. Другие файлы не могут получить от них extern

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

const double m = 30000; 

Это лучше и во многих случаях лучше всего. Если компилятор видит эту глобальную константу, а затем видит ссылку на m, то она знает, что вместо того, чтобы генерировать код для загрузки значения из того, где он когда-либо (что, вероятно, требует загрузки буквального адреса в регистр), в регистр или позицию стека для выполнения вычислений он может просто сделать регистр 30000 или иногда генерировать команду с кодировкой 30000 прямо там.

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

Я не уверен, является ли он стандартным, но иногда можно сделать extern const double m = 30000;, а компилятор будет использовать 30000 для оптимизации и предположить, что на другом файле есть копия m, которая будет сохранена в исполняемом файле. Вы также можете сделать static const double m = 30000;, и компилятор может предположить, что никто другой не ожидает, что копия m будет сохранена в объектном коде, сгенерированном из этого исходного файла.

Ведение

#define m 30000 

является более рискованным. Вы не получите предупреждение или ошибку, если ранее было другое m, объявленное как переменная, константа или функция. Кроме того, для макросов препроцессора, подобных этому, легко испортиться. Например:

#define BASE_ADDRESS 48 
#define MY_OFFSET 9 
#define MY_ADDRESS BASE_ADDRESS+MY_OFFSET 
... 
    return MY_ADDRESS*4; 

Да, это глупый пример, но то, что это выглядит как после того, как препроцессор будет сделано с ним

... 
    return 48+9*4; 

Что

return 48+(9*4); 

И это не то, что вы, вероятно, хотели.

Другое место, где макросы плохие, - это когда у вас большие константы, такие как строки. Строки требуют, чтобы они были адресованы указателем, и их сложнее оптимизировать, чем целые числа и числа с плавающей запятой или константные числа. Вы можете легко сделать очень большую программу, если у вас много вещей, как:

#define JIM "Jim" 
#define JOHN "John" 

, а затем использовал ДЖИМ и Джон весь вашей программы, потому что компилятор не может быть в состоянии видеть, что вы на самом деле нужны только строки " Джом "и" Джон "один раз в программе.

Это, как говорится, нередко означает, что константы объявляются подобным образом, и часто они надлежащим образом выполняются таким образом людьми, которые знают, что они делают.

+0

Спасибо за длинное объяснение. Поэтому, если у меня есть все коды в одном файле, то статический const double m = 30000 является лучшим ответом, который я предполагаю. – yCalleecharan

+0

Все компиляторы распознают два строковых литерала, которые будут идентичны и будут хранить их только один раз. – Tomas

+0

В некоторых случаях вы используете 'define' вместо' const'. 'static const uint8_t ARRAY_SIZE = 16U; uint8_t array [ARRAY_SIZE] 'не работает, потому что' ARRAY_SIZE' не является явным постоянным значением. То же самое с 'const uint8_t SECONDS_PER_MINUTE = 60U; const uint16_t SECONDS_PER_HOUR = 60U * SECONDS_PER_MINUTE; ', это не работает. Это большой позор. – Gauthier

5

static для объекта, объявленного вне функции, просто делает объект локальным для единицы перевода (т. Е. К нему невозможно получить доступ из других файлов .c). Это не делает его постоянным. Для этого было const. Они ортогональны, поэтому вы можете иметь один или другой или оба.

например.

static const double m = 5; 

#define объявляет макрос, который (в данном случае) может быть использован в качестве постоянного значения. Объекта нет, поэтому const не применяется, так как нет объекта для изменения. Как следствие, вы также не можете взять адрес макроса.

+0

Просто добавьте немного: 'const' и' static' не совсем ортогональны в C++, поскольку они находятся на C. В C++ переменная 'const', определенная вне функции, также по умолчанию является' static'. –

+0

@ Джерри: Конечно, но это вопрос С и вопрос начинающего, поэтому это, вероятно, деталь, которая не стоит усложнять ответ. –

+0

Является ортогональным правильным словом? Или вы имели в виду взаимное отношение? так как мы сказали, что можем либо один, либо другой или оба. – yCalleecharan

7

static означает, что переменная будет иметь статическую продолжительность хранения и локальную видимость. В этом случае он используется для части «локальной видимости» этого, т. Е. Означает, что m видна только внутри этой единицы перевода (по существу, этот файл после его форматирования).

1

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

Разница между использованием const и #define заключается в том, что первая позволяет компилятору вводить проверку использования вами константы.

1

Основное отличие состоит в том, что при #define вы оставляете систему типов. Препроцессор не имеет понятия безопасности типа, области действия и т. Д. Так, например, если позже вы пытаетесь написать цикл, как

для (INT т = 0, м < размера, м ++) {...}

вы до неприятного сюрприза ...

также если вы используете #defines, вы увидите только значение 30000 при отладке кода, а не имя m. Это не имеет большого значения в этом случае, но при использовании значимых констант и имен переменных это действительно так.

+0

Спасибо. Интересно узнать об этом отладке. – yCalleecharan

2

...Изменение/инициализировать каждый раз, когда вызывается функция

Вы можете использовать слова «изменение» и «инициализации», как если бы они были такими же, но они не являются

void f(void) { 
    static int a = 0; 
    a++; // changed! 
    printf("%d\n", a); 
} 

int main(void) { 
    f(); f(); 
} 

/* 
    # 1 
    # 2 
*/ 

Когда в файловой области видимости (внешние функции) static не означает «const», как в «статическом значении», но это означает, что идентификатор может упоминаться только в этой единице перевода.

Итак, ваши первые m без const все еще могут быть изменены. Только const защитники от изменений. Но если вы опустите static, то если вы свяжетесь в библиотеке или другом объектном файле, который имеет тот же нестатический идентификатор в области файлов, вы получите конфликты во время ссылки.

2

#define - операция препроцессора и приведет к замене всех вхождений m на 30000 до того, как будет выполнена фаза компиляции. Два других примера являются добросовестными переменными. Переменная static существует в блоке трансляции, в котором она объявлена, и может быть изменена. Переменная const доступна только для чтения.

5

Когда вы пишете const double m=3000;, вы сообщаете компилятору создать в объектном файле символ m, к которому можно получить доступ из других файлов. Компилятор может включить значение m в файл, где он определен, но символ еще имеет, который будет выделен для целей отдельной компиляции.

При написании #define m 3000 вы просто используете синтаксическое удобство для записи одной и той же константы в нескольких местах исходного файла.

2

Если значение m должен остаться тот же навсегда, то, конечно, вы можете использовать либо

static const double m = 30000; 

или

#define m 30000 

Сразу отметим, что в C const объекты имеют внешнее связывание по умолчанию , поэтому для получения эквивалентной декларации const вы должны использовать static const, а не только const.

Также обратите внимание, что на языке C const объекты не являются константами, а скорее являются «постоянными переменными». Если вам нужна настоящая константа (т. Е. Объект, который формирует постоянные выражения ), вы должны использовать либо , либо константу перечисления.

Последний, как правило, является проблемой только с интегральными константами. В вашем случае double подход с [static] const может работать лучше всего.

Смежные вопросы