Что такое "статическая" функция?
Вопрос был о простой c функции, а не С++ static
методы, как выяснено в комментариях.
Хорошо, я понимаю, что такое переменная static
, но что такое функция static
?
И почему это так, что если я объявляю функцию, скажем void print_matrix
, пусть говорит a.c
(БЕЗ a.h
) и включает "a.c"
- я получаю "[email protected]@....) already defined in a.obj"
, НО если я объявляю это как static void print_matrix
, тогда он компилируется?
ОБНОВЛЕНИЕ Просто для того, чтобы прояснить ситуацию - я знаю, что включение .c
является плохим, как многие из вас указали. Я просто делаю это, чтобы временно освободить место в main.c
, пока у меня не будет лучшего представления о том, как сгруппировать все эти функции в правильные файлы .h
и .c
. Просто временное, быстрое решение.
Ответы
Ответ 1
static
функции - это функции, которые видны только для других функций одного и того же файла (более точно такая же единица перевода).
EDIT. Для тех, кто думал, что автор вопросов означал "метод класса": поскольку вопрос помечен C
, он означает обычную старую функцию C. Для методов класса (С++/Java/...) static
означает, что этот метод можно вызвать в самом классе, нет экземпляра этого класса.
Ответ 2
Существует большая разница между статическими функциями в C и статическими функциями-членами в С++. В C статическая функция не видна вне ее единицы перевода, которая является объектным файлом, в который она скомпилирована. Другими словами, статическая функция функции ограничивает ее объем. Вы можете представить статическую функцию как "private" в ее *.c файл (хотя это не совсем правильно).
В С++ "static" также может применяться к функциям-членам и членам данных классов. Статический элемент данных также называется "переменной класса", а элемент нестатического данных - "переменная экземпляра". Это терминология Smalltalk. Это означает, что существует только одна копия элемента статических данных, разделяемая всеми объектами класса, в то время как каждый объект имеет свою собственную копию нестатического элемента данных. Таким образом, статический член данных по существу является глобальной переменной, являющейся членом класса.
Нестатические функции-члены могут обращаться ко всем членам данных класса: статические и нестатические. Статические функции-члены могут работать только со статическими элементами данных.
Один из способов подумать о том, что в С++ статические члены данных и статические функции-члены не принадлежат ни одному объекту, но всему классу.
Ответ 3
Существует два варианта использования ключевого слова static, когда речь идет о функциях в С++.
Во-первых, чтобы отметить функцию как имеющую внутреннюю связь, поэтому ее нельзя ссылаться в других единицах перевода. Это использование устарело в С++. Для этого использования предпочтительны пространства имен.
// inside some .cpp file:
static void foo(); // old "C" way of having internal linkage
// C++ way:
namespace
{
void this_function_has_internal_linkage()
{
// ...
}
}
Второе использование относится к классу. Если класс имеет статическую функцию-член, это означает, что функция является членом класса (и имеет обычный доступ к другим членам), но не может быть вызвана через конкретный объект. Другими словами, внутри этой функции нет указателя "this".
Ответ 4
Пример минимальной работоспособной многофайловой области
Здесь я иллюстрирую, как static
влияет на объем определений функций в нескольких файлах.
переменный ток
#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;
}
GitHub вверх по течению.
Скомпилируйте и запустите:
gcc -c a.c -o a.o
gcc -c main.c -o main.o
gcc -o main main.o a.o
./main
Выход:
main f
main sf
main f
a sf
интерпретация
- есть две отдельные функции
sf
, по одной для каждого файла - есть одна общая функция
f
Как обычно, чем меньше область действия, тем лучше, поэтому всегда объявляйте static
функции, если можете.
В программировании на C файлы часто используются для представления "классов", а static
функции представляют "частные" методы класса.
Обычный C-шаблон - передавать this
структуру в качестве первого аргумента "method", что в основном и делает то, что C++ делает под капотом.
Что говорят об этом стандарты
C99 N1256 черновик 6.7.1 " Спецификаторы класса хранения" говорит, что static
является "спецификатором класса хранения".
6.2.2/3 "Связи идентификаторов" говорит, что static
подразумевает internal linkage
:
Если объявление идентификатора области файла для объекта или функции содержит статический спецификатор класса хранения, идентификатор имеет внутреннюю связь.
и 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
оптимизацию с помощью -O3
, символ sf
полностью удаляется из таблицы символов: его нельзя использовать извне. TODO зачем вообще хранить статические функции в таблице символов, когда нет оптимизации? Могут ли они быть использованы для чего-либо?
Смотрите также
C++ анонимные пространства имен
В C++ вы можете захотеть использовать анонимные пространства имен вместо статических, что дает аналогичный эффект, но дополнительно скрывает определения типов: Безымянный/анонимный пространства имен против статических функций
Ответ 5
Ниже перечислены простые функции C - в классе С++ модификатор "static" имеет другое значение.
Если у вас есть только один файл, этот модификатор не имеет абсолютно никакого значения. Разница заключается в больших проектах с несколькими файлами:
В C каждый "модуль" (комбинация sample.c и sample.h) скомпилируется независимо, а затем каждый из скомпилированных объектных файлов (sample.o) связывается вместе с исполняемым файлом компоновщиком.
Скажем, у вас есть несколько файлов, которые вы включаете в свой основной файл, а два из них имеют функцию, которая используется только для удобства под названием add(int a, b)
- компилятор будет легко создавать объектные файлы для этих двух модулей, но компоновщик будет вызывать ошибку, потому что он находит две функции с тем же именем и не знает, какой из них он должен использовать (даже если нет ссылки, потому что они не используются где-то еще, а в собственном файле).
Вот почему вы делаете эту функцию, которая используется только внутри, статическая функция. В этом случае компилятор не создает типичную ссылку "вы можете связать эту вещь" -flag для компоновщика, так что компоновщик не видит эту функцию и не будет генерировать ошибку.
Ответ 6
Первое: обычно плохая идея включать файл .cpp
в другой файл - это приводит к таким проблемам :-) Обычный способ - создать отдельные модули компиляции и добавить файл заголовка для включенного файла.
Во-вторых:
C++ имеет здесь некоторую запутанную терминологию - я не знал об этом, пока не было указано в комментариях.
а) static functions
- унаследованные от C, и о чем вы здесь говорите. Вне любого класса. Статическая функция означает, что она не видна за пределами текущего модуля компиляции - поэтому в вашем случае a.obj имеет копию, а ваш другой код имеет независимую копию. (Вздутие окончательного исполняемого файла с несколькими копиями кода).
б) static member function
- то, что объектная ориентация называет статическим методом. Живет внутри класса. Вы вызываете это с помощью класса, а не через экземпляр объекта.
Эти два разных определения статических функций совершенно разные. Будьте осторожны - здесь будут драконы.
Ответ 7
статические функции определяют этот символ как внутренний. Таким образом, он не будет виден для связи извне, но только с функциями в одном модуле компиляции, обычно в том же файле.
Ответ 8
Статическая функция - это функция, которая может быть вызвана самим классом, в отличие от экземпляра класса.
Например, нестатический:
Person* tom = new Person();
tom->setName("Tom");
Этот метод работает над экземпляром класса, а не с самим классом. Однако у вас может быть статический метод, который может работать без экземпляра. Это иногда используется в шаблоне Factory:
Person* tom = Person::createNewPerson();
Ответ 9
Ответ на статическую функцию зависит от языка:
1) В языках без OOPS, таких как C, это означает, что функция доступна только в файле, где он определен.
2) В языках с OOPS, такими как С++, это означает, что функция может быть вызвана непосредственно в классе без создания экземпляра.
Ответ 10
Минус nit: статические функции видны для единицы перевода, которая для большинства практических случаев - это файл, в котором функция определена. Ошибка, которую вы получаете, обычно называется нарушением правила One Definition.
Стандарт, вероятно, говорит что-то вроде:
"Каждая программа должна содержать ровно одно определение каждой неинлинной функция или объект, который используется в этой программе; нет диагностических требуется."
Это способ взглянуть на статические функции. Однако это устарело на С++.
В С++, кроме того, вы можете объявлять функции-члены static. Это, в основном, метафунции, т.е. Они не описывают/не изменяют поведение/состояние конкретного объекта, а действуют на весь класс. Кроме того, это означает, что вам не нужно создавать объект для вызова статической функции-члена. Кроме того, это также означает, что вы получаете доступ к статическим переменным-членам из такой функции.
Я бы добавил к примеру Parrot шаблон Singleton, основанный на такой статической функции-члене, чтобы получить/использовать один объект на протяжении всего жизненного цикла программы.
Ответ 11
для статической функции в компиляторе "c" не будет создавать свои внутренние переменные в стеке, поэтому вызов статической функции выполняется быстрее, и, как следствие, вы не можете использовать инициализаторы, такие как: char c = 'A'.