Подтвердить что ты не робот

Static, define и const в C

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

#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 в нужный тип данных.

4b9b3361

Ответ 1

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

Затем все вызовы в бар изменят 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"

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

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

Ответ 2

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

Ответ 3

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

например.

static const double m = 5;

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

Ответ 4

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

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

Ответ 5

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

Вы используете слова "change" и "initialize", как если бы они были одинаковыми, но они не являются

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

Ответ 6

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

Ответ 7

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

static const double m = 30000; 

или

#define m 30000

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

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

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

Ответ 8

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

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

Ответ 9

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

for (int m = 0; m < size; m ++) {...}

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

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