Xcode 8.3.1 - Swift 3
Это принятый ответ paulvs, преобразованный в Swift 3:
let myGroup = DispatchGroup()
override func viewDidLoad() {
super.viewDidLoad()
for i in 0 ..< 5 {
myGroup.enter()
Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"]).responseJSON { response in
print("Finished request \(i)")
myGroup.leave()
}
}
myGroup.notify(queue: DispatchQueue.main, execute: {
print("Finished all requests.")
})
}
Ошибка компиляции вызвана тем, что в функции func1 () есть дублированное определение;
Поскольку func1 () определяется с использованием extern inline, он создаст внешнее определение.
Однако в файле tran.c также есть внешнее определение, которое вызывает ошибку множественного определения.
Однако, func2 () и func3 () не создают внешнего определения, следовательно, нет ошибки переопределения.
Вы можете посмотреть здесь http://www.greenend.org.uk/rjk/2003/03/inline.html .
Кроме того, обратите внимание, что c ++ и c по-разному относятся к встроенным функциям, и даже в c разные стандарты (c89 и c99) по-разному относятся к встроенным функциям.
Этот ответ состоит из следующих разделов:
duplicate definition of inline function - func3
и почему. func3
является дубликатом вместо func1
. g++
Эта проблема может быть успешно воспроизведена
tran.cpp
в tran.c
gcc -o main main.c tran.c
@ K71993 фактически компилируется с использованием старой встроенной семантики gnu89, которая отличается от C99. Причиной переименования tran.cpp
в tran.c
является указание драйверу gcc трактовать его как источник C
вместо источника C++
.
Следующий текст процитирован из Документ GCC: встроенная функция выполняется так же быстро, как макрос , объясняет, почему func3
является дублирующим определением вместо func1
], поскольку func3
(вместо func1
) является внешне видимым символом (во встроенной семантике GNU89)
Если встроенная функция не является статической, то компилятор должен предполагать, что могут быть звонки из других исходных файлов; поскольку глобальный символ может быть определен только один раз в любой программе, функция не должна быть определена в других исходных файлах , поэтому вызовы в них не могут быть интегрированы. Поэтому нестатическая встроенная функция всегда компилируется сама по себе обычным способом.
Если вы укажете как inline, так и extern в определении функции , то это определение используется только для встраивания. Ни в коем случае функция не компилируется сама по себе, даже если вы явно ссылаетесь на ее адрес. Такой адрес становится внешней ссылкой, как если бы вы только объявили функцию и не определили ее.
Если компилируется со стандартом C99, т.е. gcc -o main main.c tran.c -std=c99
, компоновщик будет жаловаться, что определение func1
является дубликатом из-за причины, по которой extern inline в C99 - это внешнее определение, упомянутое в других постах и комментариях.
Также см. этот отличный ответ о семантических различиях между GNU89 inline
и C99 inline.
g++
. При компиляции с g++
исходная программа рассматривается как C++
источник. Поскольку func1
, func2
и func3
определены в нескольких единицах перевода, а их определения различны, одно правило определения для C ++ нарушается. Поскольку компилятору не требуется генерировать сообщение с достоинством, когда определения охватывают несколько единиц перевода, поведение не определено.
Ваш код недопустим с точки зрения C ++, поскольку он явно нарушает Правило Единого Определения. Единственная причина, по которой вам удалось скомпилировать его с помощью компилятора C ++, - это свободная проверка ошибок в вашем компиляторе C ++ (это одна из тех частей ODR, где «диагностика не требуется»).
Ваш код не является допустимым C, поскольку он обеспечивает дублирование внешнего определения функции func1
. Заметим, что с точки зрения C проблематично func1
, а не func3
. Там нет ничего формально не так с вашим func3
. Ваш func2
также в порядке, если два определения никогда не «встречаются» друг с другом в одной и той же единице перевода.
Одной из возможных причин, по которой вы можете получить другой диагностический отчет от вашего компилятора, является то, что ваш компилятор C может поддерживать inline
функции некоторым нестандартным для компилятора способом (либо компилятором до C99, либо запуском современного компилятора). в нестандартном «традиционном» режиме).
Честно говоря, мне трудно поверить, что вы получаете сообщение об ошибке func3
от любого компилятора, если предположить, что код, который вы разместили, точно представляет то, что вы пытаетесь скомпилировать. Скорее всего, вы написали , а не реальный код.
Может быть, вы должны опубликовать фактический код. Фрагменты, которые вы показываете, не компилируются:
extern inline int func1(void)
Это не имеет никакого смысла. #define <stdio.h>
Я думаю, что вы имели в виду include
вместо. Как только я исправил их и скомпилировал с помощью gcc, он скомпилировался нормально, и я получил следующий вывод
5
6
7
Когда я скомпилировал с g ++, я получил такой вывод:
5
6
700
Это происходит потому, что func3 () не является статическим в inline.h
Ошибка компиляции, которую вы видите, на самом деле является ошибкой компоновщика.
gcc и g ++ трактуют static inline
немного по-другому. inline
была сначала частью C ++, а затем превращена в расширение для многих компиляторов C, прежде чем была добавлена в стандарт C. Стандартная семантика может отличаться, но это могут быть просто разные реализации.
Это также может иметь какое-то отношение к каким-то безумным вещам, которые происходят с кодом C ++, который избавляется от дублирующихся шаблонов, ловящих другие дублирующиеся вещи.
В основном Inline - поздняя запись в GCC (я имею в виду c-компилятор). «[....] Встроенное определение не предоставляет внешнего определения для функции и не запрещает внешнее определение в другой единице перевода. Встроенное определение предоставляет альтернативу внешнему определению, которое переводчик может использовать для реализации любого вызов функции в том же модуле перевода. Не определено, использует ли вызов функции встроенное определение или внешнее определение. " - ISO 9899: 1999 (E), стандарт C99, раздел 6.7.4