Разница между исполняемыми файлами C и C ++?

Я знаю, что есть различия в исходном коде между программами C и C ++ — это не о чем я спрашиваю

Я также знаю, что это будет варьироваться от процессора к процессору и ОС к ОС, в зависимости от компилятора.

Я учу себя C ++, и я видел многочисленные ссылки на библиотеки, которые могут использоваться обоими языками. Это заставило меня задуматься — есть ли существенные различия между двоичными исполняемыми файлами двух языков?

Чтобы библиотеки могли легко использоваться обеими, я бы подумал, что они должны быть похожи на исполняемом уровне.

Много ли ситуаций, когда человек может проверить исполняемый файл и сказать, был ли он создан на основе исходного кода C или C ++? Или двоичные файлы будут очень похожи?

2

Решение

В большинстве случаев да, это довольно легко. Вот лишь несколько подсказок, которые я видел достаточно часто, чтобы легко их запомнить:

  1. Программа на C ++ обычно заканчивается как минимум несколькими видимыми символами, которые были искажены.
  2. Программа на C ++ обычно имеет по крайней мере мало вызовы виртуальных функций, которые обычно отличаются от кода, который вы обычно видите на C.
  3. Многие компиляторы C ++ реализуют соглашение о вызовах для C ++, в котором особое внимание уделяется передаче this указатель на функции-члены C ++. Опять же, так как this Указатель просто не существует в C, вы редко увидите прямой аналог (хотя в некоторых случаях они будут использовать то же соглашение для передачи какого-либо другого указателя, поэтому вам нужно быть осторожным с этим).
6

Другие решения

Исполняемый файл — это исполняемый файл, независимо от того, на каком языке он написан. Если он создан для целевой архитектуры, он будет работать на архитектуре.

(Возможно) самое важное различие между C и C ++ — скомпилированным кодом, и то, что относится к библиотекам, которые могут быть связанный как для C, так и для C ++, это искажение имени. В основном: когда библиотека компилируется, она экспортирует набор символов (имена функций, экспортированные переменные и т. Д.), Которые могут использовать исполняемые файлы, связанные с библиотекой. Как эти символы названный является довольно специфичным для компилятора / компоновщика, и если последующий исполняемый файл связан с помощью компоновщика с использованием несовместимого соглашения, то символы не будут разрешаться правильно. Кроме того, C и C ++ имеют несколько разные соглашения. Ссылка на статью в Википедии содержит больше деталей; Достаточно сказать, что при объявлении экспортированных символов в заголовочном файле вы обычно увидите такую ​​конструкцию, как:

#ifdef __cplusplus
extern "C" {
#endif

/* exported declarations here */

#ifdef __cplusplus
}
#endif

__cplusplus макрос препроцессора, определенный только при компиляции кода C ++ Идея здесь заключается в том, что при использовании заголовка в C ++, компилятор проинструктирован использовать способ именования экспортируемых символов C (внутриextern "C" { /* foo */ }msgstr «блок, поэтому библиотека может быть правильно связана как на C, так и на C ++.

4

я считать Я мог бы сказать, является ли что-то C ++ или C по чтению дизассемблированного двоичного кода [для архитектур процессоров, с которыми я знаком, x86, x86_64 и ARM]. Но на самом деле, нет большой разницы, вам наверняка придется выглядеть довольно сложно.

Знаки для поиска являются «косвенными вызовами» (function pointer calls via a table) а также this-pointers. Хотя С может иметь pointer to struct аргументы и часто используют указатели на функции, обычно это не настраивается так, как это делает C ++. Кроме того, иногда вы замечаете, что компилятор берет указатель на структуру и добавляет небольшое смещение — это удаляет внешний слой унаследованного класса. Это может произойти и в C, но оно не будет таким распространенным.

Смотреть только на двоичный файл [если вы не можете «сделать разборку в своей голове», было бы намного сложнее — особенно если бы он был лишен символов — это похоже на парня, который мог бы сказать вам, что классическая музыка была на старой виниловой пластинке, если посмотреть на треках [со скрытым лейблом] — не то, что большинство людей могут сделать, даже если они «хороши».

2

На практике, программа на C (или программа на C ++) редко является только чистым стандартом C (или C ++) (например, стандарт C99 не предназначен для сканирования каталога). Так что программы используют дополнительные библиотеки.

В Linux большинство двоичных файлов динамически связаны. Использовать ldd Команда, чтобы узнать.

Если бинарный файл связан с stdc++ библиотека, исходный код, вероятно, C ++.

Если бы только libc.so библиотека связана, исходный код, вероятно, только C (но вы можете статически связать libstdc++.a библиотека).

Вы также можете использовать инструменты, работающие с двоичными файлами (например, objdump, readelf, strings, nm на Linux ….), чтобы узнать больше о них.

1

Код, сгенерированный компиляторами C и C ++, обычно является одним и тем же кодом. Есть два важных различия:

  • Изменение имени: каждая функция и глобальная переменная становятся условное обозначение во время компиляции. В C имена этих символов совпадают с именами в вашем исходном коде. В C ++ они немного искажены, чтобы учесть полиморфный код
  • Соглашения о вызовах: если вы вызываете метод в C ++, указатель this передается как скрытый первый параметр. Другие соглашения могут также отличаться, такие как вызов по ссылке, который не существует в C

Вы можете использовать такой блок, чтобы компилятор C ++ генерировал код, совместимый с C:

extern "C" {
/* code */
}
1
По вопросам рекламы [email protected]