Что такое "статическая функция"?
вопрос был о простом c функции, а не c++ static
методы, как поясняется в комментариях.
хорошо, я понимаю, что static
переменная есть, но что такое ?
и почему, если я объявляю функцию, скажем void print_matrix
, скажем a.c
(без a.h
) и "a.c"
- Я "print_matrix@@....) already defined in a.obj"
, но если я объявлю это как static void print_matrix
затем он компилирует?
обновление Просто чтобы прояснить ситуацию - я знаю, что в том числе .c
плохо, как многие из вас заметили. Я просто делаю это, чтобы временно очистить пространство в main.c
пока у меня нет лучшего представления о том, как сгруппировать все эти функции в правильные .h
и .c
файлы. Просто временное, быстрое решение.
11 ответов
static
функции-это функции, которые видны только другим функциям в том же файле (точнее тот же ЕП).
редактировать: для тех, кто думал, что автор вопросов имел в виду "метод класса": поскольку вопрос помечен C
Он имеет в виду простую старую функцию C. For (C++ / Java/...) методы класса,static
означает, что этот метод может быть вызван для самого класса, без экземпляра этого класса необходимый.
существует большая разница между статическими функциями в C и статическими функциями-членами в C++. В C статическая функция не видна за пределами ее единицы перевода, которая является объектным файлом, в который она скомпилирована. Другими словами, статичность функции ограничивает ее область действия. Вы можете думать о статической функции как о "частной" для ее *.C файл (хотя это не совсем правильно).
в C++ "static" также может применяться к функциям-членам и членам данных классов. Ля статический элемент данных также называется "переменной класса", а нестатический элемент данных-"переменной экземпляра". Это терминология Smalltalk. Это означает, что существует только одна копия статического члена данных, которые используются всеми объектами класса, в то время как каждый объект имеет собственную копию нестатический член данных. Таким образом, статический член данных по существу является глобальной переменной, то есть членом класса.
нестатические функции-члены могут получить доступ ко всем данным-членам класса: статические и нестатический. Статические функции-члены могут работать только со статическими элементами данных.
один из способов подумать об этом заключается в том, что в C++ статические члены данных и статические функции-члены принадлежат не какому-либо объекту, а всему классу.
есть два использования для ключевого слова static, когда дело доходит до функций в C++.
первый-отметить функцию как имеющую внутреннюю связь, чтобы на нее нельзя было ссылаться в других единицах перевода. Это использование устарело в C++. Для этого предпочтительны неназванные пространства имен.
// inside some .cpp file:
static void foo(); // old "C" way of having internal linkage
// C++ way:
namespace
{
void this_function_has_internal_linkage()
{
// ...
}
}
второе использование находится в контексте класса. Если класс имеет статическую функцию-член, это означает, что функция является членом класса (и имеет обычный доступ к другие члены), но его не нужно вызывать через определенный объект. Другими словами, внутри этой функции нет указателя" это".
минимальный запускаемый многофайловый пример
а.с:
#include <stdio.h>
/*
Undefined behavior: already defined in main.
Binutils 2.24 gives an error and refuses to link.
https://stackoverflow.com/questions/27667277/why-does-borland-compile-with-multiple-definitions-of-same-object-in-different-c
*/
/*void f() { puts("a f"); }*/
/* OK: only declared, not defined. Will use the one in main. */
void f(void);
/* OK: only visible to this file. */
static void sf() { puts("a sf"); }
void a() {
f();
sf();
}
main.c:
#include <stdio.h>
void a(void);
void f() { puts("main f"); }
static void sf() { puts("main sf"); }
void m() {
f();
sf();
}
int main() {
m();
a();
return 0;
}
сборник:
gcc -c a.c -o a.o
gcc -c main.c -o main.o
gcc -o main main.o a.o
выход:
main f
main sf
main f
a sf
толкование
- Есть две отдельные функции
sf
, по одному для каждого файла - Есть одна общая функция
f
как обычно, чем меньше объем, тем лучше, поэтому всегда объявляйте функции static
если вы можете.
в программировании на C файлы часто используются для представления "классов" и static
функции представляют собой "частные" методы класса.
общий шаблон C должен пройти this
struct вокруг как первый аргумент "метода", который в основном является тем, что C++ делает под капотом.
что говорят стандарты о это
С99 проект N1256 6.7.1 "спецификаторы класса хранения" говорит, что static
- это "описатель хранени-класса".
6.2.2 / 3 "связи идентификаторов" говорит static
подразумевает internal linkage
:
если объявление идентификатора объем файла для объекта или функции содержит спецификатор класса хранения static, то идентификатор имеет внутренние связи.
и 6.2.2/2 говорит, что internal linkage
ведет себя как в наш пример:
в наборе единиц перевода и библиотек, составляющих целую программу, каждое объявление определенного идентификатора с внешней связью обозначает один и тот же объект или функцию. В пределах одной единицы перевода каждое объявление идентификатора с внутренней связью обозначает один и тот же объект или функцию.
где "единица перевода" - исходный файл после предварительной обработки.
как GCC реализует его для ELF (Linux)?
С STB_LOCAL
привязка.
если мы компилируем:
int f() { return 0; }
static int sf() { return 0; }
и разобрать таблицу символов с помощью:
readelf -s main.o
вывод содержит:
Num: Value Size Type Bind Vis Ndx Name
5: 000000000000000b 11 FUNC LOCAL DEFAULT 1 sf
9: 0000000000000000 11 FUNC GLOBAL DEFAULT 1 f
таким образом, связывание является единственным значительным различием между ними. Value
просто их смещение в .bss
раздел, поэтому мы ожидаем, что он будет отличаться.
STB_LOCAL
документировано на спецификации ELF на http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html:
Stb_local локальные символы не видны за пределами объектного файла, содержащего их определение. Локальные символы с одинаковым именем могут существовать в нескольких файлах, не мешая друг другу
что делает его идеальным выбором для представления static
.
функции без статических являются STB_GLOBAL
, а спец говорит:
когда редактор ссылок объединяет несколько перемещаемых объектных файлов, он не позволяет использовать несколько определений символов STB_GLOBAL с одинаковым именем.
что согласуется с ошибками ссылки на несколько нестатических определений.
если мы провернем оптимизацию с помощью -O3
, the sf
символ полностью удаляется из таблицы символов: его нельзя использовать извне в любом случае. TODO зачем вообще хранить статические функции в таблице символов, когда их нет оптимизация? Их можно использовать для чего угодно?
см. также
- же для переменных: https://stackoverflow.com/a/14339047/895245
-
extern
напротивstatic
, а функции ужеextern
по умолчанию: как использовать extern для обмена переменными между исходными файлами?
попробуйте сами
пример На GitHub для вас, чтобы играть.
следующее касается простых функций C - в классе c++ модификатор 'static' имеет другое значение.
Если у вас есть только один файл, то этот модификатор не имеет абсолютно никакого значения. Разница заключается в больших проектах с несколькими файлами:
В C, каждый "модуль" (комбинация образца.C и образец.h) компилируется независимо, а затем каждый из этих скомпилированных объектных файлов (образец.o)связаны вместе с исполняемым файлом компоновщиком.
предположим, у вас есть несколько файлов, которые вы включаете в свой основной файл, и два из них имеют функцию, которая используется только внутри для удобстваadd(int a, b)
- компилятор легко создаст объектные файлы для этих двух модулей, но компоновщик выдаст ошибку, потому что он найдет две функции с одинаковым именем и не знает, какую из них он должен использовать (даже если нет ничего, чтобы связать, потому что они не используются где-то еще, но в своем собственном папка.)
вот почему вы делаете эту функцию, которая используется только внутренняя, статической функцией. В этом случае компилятор не создает типичный флаг"вы можете связать эту вещь" для компоновщика, чтобы компоновщик не видел эту функцию и не генерировал ошибку.
во-первых: вообще плохая идея включить .cpp
файл в другом файле-это приводит к таким проблемам, как: -) обычный способ-создать отдельные единицы компиляции и добавить файл заголовка для включенного файла.
во-вторых:
C++ имеет некоторую запутанную терминологию здесь - я не знал об этом, пока не указал в комментариях.
a)static functions
- унаследовано от C, и о чем вы здесь говорите. Вне любого класса. Статика функции означает, что он не виден вне текущего блока компиляции - так что в вашем случае a.obj имеет копию, а ваш другой код имеет независимую копию. (Раздувание окончательного исполняемого файла с несколькими копиями кода).
b)static member function
- какие термины объектной ориентации статические метод. Живет внутри класса. Вы вызываете это с классом, а не через экземпляр объекта.
эти две разные статические функции определения совершенно разные. Будьте осторожны-здесь будут драконы.
определения статических функций пометят этот символ как внутренний. Поэтому он не будет виден для связывания извне, а только для функций в том же блоке компиляции, обычно в том же файле.
статическая функция-это функция, которая может быть вызвана в самом классе, в отличие от экземпляра класса.
например нестатический будет такой:
Person* tom = new Person();
tom->setName("Tom");
этот метод работает на экземпляре класса, а не на самом классе. Однако у вас может быть статический метод, который может работать без экземпляра. Это иногда используется в Заводском шаблоне:
Person* tom = Person::createNewPerson();
Minor nit: статические функции видны единице перевода, которая для большинства практических случаев является файлом, в котором определена функция. Ошибка, которую вы получаете, обычно называется нарушением правила одного определения.
стандарт, вероятно, говорит что-то вроде:
" каждая программа должна содержать ровно одно определение каждой неинлайн функция или объект, который используется в этой программе; диагностики требуемый."
Это способ c смотреть на статические функции. Однако это устарело в C++.
в C++, кроме того, вы можете объявить функции-члены статическими. Это в основном метафункции, т. е. они не описывают/изменяют поведение / состояние конкретного объекта, а действуют на весь класс. Кроме того, это означает, что вам не нужно создавать объект для вызова статической функции-члена. Кроме того, это также означает, что вы получаете доступ только к статическим членам переменные в рамках такой функции.
Я бы добавил к примеру Parrot шаблон Singleton, который основан на такой статической функции-члене, чтобы получить/использовать один объект в течение всего срока службы программы.
ответ на статическую функцию зависит от языка:
1) в языках без OOPS, таких как C, это означает, что функция доступна только в файле, где она определена.
2) в языках с OOPS , таких как C++, это означает, что функция может вызываться непосредственно в классе без создания экземпляра.
для статической функции в компиляторе" c " не будет создавать свои внутренние переменные в стеке, поэтому вызов статической функции происходит быстрее, и, как следствие, вы не можете использовать инициализаторы типа: char c='A'.