статические переменные во встроенной функции
У меня есть функция, которая объявлена и определена в заголовочном файле. Это проблема сама по себе. Когда эта функция не встроена, каждая единица перевода, которая использует этот заголовок, получает копию функции, и когда они связаны вместе, они дублируются. Я " исправил "это, сделав функцию встроенной, но я боюсь, что это хрупкое решение, потому что, насколько я знаю, компилятор не гарантирует встраивание, даже когда вы указываете ключевое слово" inline". Если это не правда, пожалуйста, поправьте меня.
в любом случае, реальный вопрос заключается в том, что происходит со статическими переменными внутри этой функции? Сколько копий я получу в итоге?
9 ответов:
Я думаю, вы что-то упускаете, здесь.
статическая функция?
объявление функции статической сделает ее "скрытой" в своем блоке компиляции.
имя, имеющее область пространства имен (3.3.6), имеет внутреннюю связь, если это имя
- переменная, функция или шаблон функции, который явно объявлен статическим;
3.5 / 3-C++14 (n3797)
когда имя имеет внутреннюю связь, сущность это на обозначения можно ссылаться по именам из других областей в той же единице перевода.
3.5 / 2-C++14 (n3797)
если объявить статическую функцию в заголовке, то все единицы компиляции, включая этот заголовок будет иметь свою собственную копию функции.
дело в том, что если есть статические переменные внутри функции, каждая единица компиляции, включая этот заголовок также будет иметь свою собственную, личную версию.
inline функции?
объявление его встроенным делает его кандидатом для встраивания (это не значит много в настоящее время в C++, так как компилятор будет встроенным или нет, иногда игнорируя тот факт, что ключевое слово inline присутствует или отсутствует):
объявление функции (8.3.5, 9.3, 11.3) со встроенным спецификатором объявляет встроенную функцию. Встроенный спецификатор указывает, что реализация подстановки тела функции в точке вызова следует предпочесть обычный механизм вызова функции. Реализация не требуется для выполнения этой встроенной подстановки в точке вызова; однако, даже если эта встроенная подстановка опущена, другие правила для встроенных функций, определенные в 7.1.2, все равно должны соблюдаться.
7.1.2 / 2-C++14 (n3797)
в заголовке у него есть интересный побочный эффект: встроенная функция может быть определена несколько раз в одном модуле, и компоновщик просто объединит "их" в один (если они не были встроены по причине компилятора).
для статических переменных, объявленных внутри, стандарт специально говорит там один, и только один из них:
статическая локальная переменная в функции extern inline всегда ссылается на один и тот же объект.
7.1.2 / 4-C++98 / C++14 (n3797)
(функции по умолчанию extern, поэтому, если вы специально не отмечаете свою функцию как статическую, это относится к этому функция)
это имеет преимущество "статического" (т. е. он может быть определен в заголовке) без его недостатков (он существует не более одного раза, если он не встроен)
статическая локальная переменная?
статические локальные переменные не имеют связи (они не могут называться по имени вне их области), но имеют статическую длительность хранения (т. е. она является глобальной, но ее построение и разрушение подчиняются определенным правилам).
статический + встроенный?
смешивание внутренних и статика будет иметь последствия, которые вы описали (даже если функция встроена, статическая переменная внутри не будет, и вы закончите с таким количеством статических переменных, как у вас есть единицы компиляции, включая определение ваших статических функций).
ответ на дополнительный вопрос автора
так как я написал вопрос, я попробовал его с Visual Studio 2008. Я попытался включить все варианты, которые заставляют VS действовать в соответствии со стандартами, но это возможно, я что-то пропустил. Таковы результаты:
когда функция просто "inline", существует только одна копия статической переменной.
когда функция является "статической встроенной", существует столько копий, сколько есть единиц перевода.
реальный вопрос теперь заключается в том, должны ли вещи быть таким образом, или если это идиосинкразия компилятора Microsoft C++.
так что я полагаю, у вас есть что-то вроде что:
void doSomething() { static int value ; }вы должны понимать, что статическая переменная внутри функции, проще говоря, глобальная переменная, скрытая для всех, кроме области действия функции, что означает, что только функция, объявленная внутри, может достичь ее.
встраивание функции ничего не изменит:
inline void doSomething() { static int value ; }будет только одна скрытая глобальная переменная. Тот факт, что компилятор попытается встроить код, не изменит тот факт, что есть только один глобальный скрытый переменная.
теперь, если функция объявляется как static:
static void doSomething() { static int value ; }тогда он является "частным" для каждой единицы компиляции, что означает, что каждый файл CPP, включая заголовок, в котором объявлена статическая функция, будет иметь свою собственную частную копию функции, включая свою собственную частную копию глобальной скрытой переменной, таким образом, столько переменных, сколько есть единицы компиляции, включая заголовок.
добавления "инлайн" на "статическая функция" с "статическая" переменной внутри:
inline static void doSomething() { static int value ; }имеет тот же результат, что и не добавление этого" встроенного " ключевого слова, Что касается статической переменной внутри.
таким образом, поведение VC++ является правильным, и вы ошибаетесь в реальном значении "inline" и "static".
Я считаю, что компилятор создает много копий переменной, но компоновщик выбирает один и делает все остальные ссылки на него. У меня были похожие результаты, когда я попробовал эксперимент по созданию разных версий встроенной функции; если функция фактически не была встроена (режим отладки), все вызовы шли к одной и той же функции независимо от исходного файла, из которого они были вызваны.
подумайте, как компилятор на мгновение-как это может быть иначе? Каждая единица компиляции (исходный файл) не зависит от других и может быть скомпилирован отдельно; поэтому каждый должен создать копию переменной, думая, что она единственная. Компоновщик имеет возможность выйти за эти границы и настроить ссылки как для переменных, так и для функций.
Я нашел ответ Марка Рэнсома полезным - что компилятор создает много копий статической переменной, но компоновщик выбирает один и применяет его во всех единицах перевода.
в другом месте я нашел вот это:
см. [dcl.ПКТ.spec] / 4
[..] Встроенная функция с внешней связью должна иметь то же самое адрес во всех единицах трансляции. Статическая локальная переменная в extern встроенная функция всегда ссылается на то же самое объект. Строковый литерал в функция extern inline-это один и тот же объект в разных единицах перевода.
У меня нет копии стандарта для проверки, но он соответствует моему опыту изучения сборки в VS Express 2008
Это должно быть так. "static" сообщает компилятору, что вы хотите, чтобы функция была локальной для единицы компиляции, поэтому вам нужна одна копия на единицу компиляции и одна копия статических переменных на экземпляр функции.
" inline "используется для того, чтобы сообщить компилятору, что вы хотите, чтобы функция была встроена; в настоящее время он просто принимает ее как"это нормально, если есть несколько копий кода, просто убедитесь, что это одна и та же функция". Так что все разделяют статику переменная.
Примечание: этот ответ был написан в ответ на ответ оригинального плаката, размещенного для себя.
Так как я написал вопрос, я попробовал его с Visual Studio 2008. Я попытался включить все варианты, которые заставляют VS действовать в соответствии со стандартами, но, возможно, я пропустил некоторые. Таковы результаты:
когда функция просто "inline", существует только одна копия статической переменной.
когда функция является "статической встроенной", существует столько копий, сколько есть единиц перевода.
реальный вопрос теперь, насколько предполагается, что это так,или если это ideosyncracy компилятора Microsoft C++.
Я считаю, что вы будете в конечном итоге с одним на единицу перевода. У вас фактически есть много версий этой функции (и ее объявленной статической переменной), по одной для каждой единицы перевода, которая включает заголовок.
Inlining означает, что исполняемый код (инструкции) встроен в код вызывающей функции. Компилятор может сделать это независимо от того, просили ли вы его. Это не влияет на переменные (данные), объявленные в функции.
помимо любых проблем с дизайном это все может означать, так как вы уже застряли с ним, вы должны использовать статический в этом случае не встроенный. Этак все разделяют одни и те же переменные. (Статическая функция)
Static означает , что одна копия распределена по всей программе , но inline означает, что она требует одного и того же кода в течение нескольких раз в одной и той же программе, поэтому невозможно сделать переменную static внутри встроенной функции.
Comments