Что такое "статическая функция"?

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

см. также

попробуйте сами

пример На 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'.