2015-02-19 2 views
1

я следующий код в main.cppпараметр снижается при использовании C связи в C++ программы

extern "C" 
{ 
    void bar(int x, char* s); 
} 

int main() 
{ 
    bar(5, "hello"); 
} 

Обратите внимание, что функция bar объявлен как принимать два аргумента. Это компилируется и связана с статической библиотеки bar.cpp, который содержит этот код

#include <iostream> 

extern "C" 
{ 
    void bar(int x) 
    { 
     std::cout << x; 
    } 
} 

Функция Примечание bar принимает только один аргумент.

Исполняемые успешно компилируется и печатает 5

У меня есть три вопроса:

  1. не должен там быть ошибка компилятора с указанием несоответствия количества параметров?
  2. В приведенном выше сценарии, поскольку строка hello не принимается bar, когда и как она уничтожается?
  3. Полностью ли он подходит для написания и использования кода, как указано выше (параметры знания будут удалены)? В чем именно заключается семантика, связанная с падением параметра?
+2

1. нет, c очень расслаблен. он не кодирует параметры в символы. 2. https://msdn.microsoft.com/en-us/library/zkwh89ks.aspx, c вызову для вызова требуется, чтобы вызывающий пользователь очистил стек, поэтому все в порядке.если вызывающий абонент не использует его, вызывающий абонент будет очищаться после этого. 3. Правильный способ - использовать значения параметров по умолчанию. – thang

+0

Нет, это зависит от вас, чтобы сохранить заголовки в синхронизации с библиотекой. Хотя, если вы продолжаете добавлять параметры, скорее всего, это приведет к краху. –

+0

Это UB. Все может случиться. –

ответ

1

Несмотря на то, что вы указываете VS, в общем случае на вопрос о C++, компиляторах и платформах выполнения чаще задается вопрос.

1.) Вы дали указание компилятору следовать правилам вызова стиля C для вашей платформы, чтобы ссылаться на символ, не определенный в этом модуле компиляции. Затем компилятор генерирует объект, который сообщает компоновщику «звонок _bar здесь» (может быть bar в зависимости от вашей платформы), который с радостью разрешает вывод компиляции bar.cpp. Более старые соглашения на C++-вызовы приведут к искаженным именам, например barZ8intZP8char, или, что еще хуже, в зависимости от вашего компилятора, чтобы обеспечить правильную работу перегрузки. Однако более новые компиляторы, возможно, более умны (волшебны!) И могут понимать дополнительные метаданные, хранящиеся в объектном файле.

Большая проблема для многоплатформенного кода связана с упорядочением стека. На нескольких платформах параметры хранятся в обратном порядке в стеке, чем их объявление, поэтому ваш код будет снабжен адресом строки вместо целочисленного значения. Fine для печати целого числа, но приведет к (надеюсь) segfault с первым параметром, который является строкой, а второй является целым числом в объявлении функции.

2.) Это зависит от платформы, которую вы используете. Для большинства платформ, связанных с системами IA32 (x86, AMD64, IA64 и т. Д.), Вызывающий отвечает за управление параметрами в стеке. Таким образом, кадр стека, содержащий дополнительный параметр, полностью отбрасывается, когда вызов завершен. Существуют случаи оптимизации, когда это может вызвать дискретную ошибку, когда кадр используется повторно, потому что компилятор был дезинформирован относительно стека вызовов.

3.) Для прикладного программирования я считаю это плохой практикой, так как может очень сложно диагностировать ошибки. Я уверен, что кто-то обнаружил кейс к этому утверждению о бинарной совместимости; однако я бы предпочел, чтобы компилятор знал о параметрах, чтобы избежать ошибок оптимизации, упомянутых в № 2.

Смежные вопросы