Статичный, определите, и константа в 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 в правильный тип данных.

19
задан Brian Tompsett - 汤莱恩 27 November 2015 в 13:59
поделиться

9 ответов

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;
}

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

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

const double m = 30000;

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

Обратной стороной этого является то, что компилятор должен предположить, что другие исходные файлы захотят прочитать 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;

Который is

 return 48+(9*4);

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

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

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

, а затем использовали JIM и JOHN во всех ваших программах, потому что компилятор может не увидеть, что вам действительно нужны только строки «Jom» и « Джон "однажды в программе.

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

16
ответ дан 30 November 2019 в 03:12
поделиться

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

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

1
ответ дан 30 November 2019 в 03:12
поделиться

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

Вы используете слова «изменить» и «инициализировать», как если бы они были одинаковыми , но это не так

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
ответ дан 30 November 2019 в 03:12
поделиться

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

for (int m = 0; m

, вас ждет неприятный сюрприз ...

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

1
ответ дан 30 November 2019 в 03:12
поделиться

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

7
ответ дан 30 November 2019 в 03:12
поделиться

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

например.

static const double m = 5;

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

5
ответ дан 30 November 2019 в 03:12
поделиться

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

static const double m = 30000; 

или

#define m 30000

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

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

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

3
ответ дан 30 November 2019 в 03:12
поделиться

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

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

5
ответ дан 30 November 2019 в 03:12
поделиться

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

2
ответ дан 30 November 2019 в 03:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: