LINUX.ORG.RU

Линковка c89 библиотеке к c11 коду

 


1

2

Здравствуйте.

Если библиотека на писана на одной версии C а код - на другой? При статической и динамической линковке. Будет ли оно наботать?

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

★★★★★

Будет ли оно наботать?

Да.

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

Это какие-то очень специфические опции, которые ломают совместимость со стандартом.

Deleted
()
Ответ на: комментарий от Deleted

Это какие-то очень специфические опции, которые ломают совместимость со стандартом

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

Gvidon ★★★★
()
Последнее исправление: Gvidon (всего исправлений: 1)
Ответ на: комментарий от Gvidon

соглашениях о вызовах, количестве подчерков перед символами

В теории да, но на практике основные компиляторы обычно соблюдают единый C calling convention и name mangling.

archie
()

Какие еще опции могут поломать совместимость?

Навскидку могу еще вспомнить wchar_t. В gcc он 4 байта по умолчанию, а в M$VC - 2. А вообще Си библиотеки имеют весьма хорошую бинарную совместимость. У меня например VLC, собранный MinGW под онтопиком, отлично подхватывается штудийным компилером.

archie
()
Ответ на: комментарий от archie

Кстати, насчет _t. Есть смысл полностью отказываться от int, char, float.. в пользу всяких uint8_t? И есть ли смысл их использовать в случаях когда библиотечная функция требует тип без _t?

makoven ★★★★★
() автор топика
Ответ на: комментарий от ilammy

Я везде читаю что MS вообще забил на сишный компилер и остановился на 89 стандарте. И агитирует всех переходить на C++ )

makoven ★★★★★
() автор топика
Ответ на: комментарий от makoven

Кстати, на счет хлеба. Есть ли смысл полностью отказываться от черного хлеба в пользу белого? И есть ли смысл кушать черный хлеб в случае, когда еда подается уже с ним?

anonymous
()

В общем случае, насколько понимаю, ответ отрицательный. Например, между C++03 и C++11 в гнутой реализации STL изменили определение std::list (в одном количество элементов хранится явно, в другом — каждый раз высчитывается за линию). И от таких факапов стандарт не страхует: формально ты нарушаешь ODR, поскольку в одной программе есть два различных определения std::list.

intelfx ★★★★★
()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от anonymous

Я понял метафору. Но ввели же эти типы зачем-то. Может есть некие best practices с ними связанные

makoven ★★★★★
() автор топика
Ответ на: комментарий от makoven

Отказываться смысла нет. На практике везде используются базовые типы, если точная разрядность не играет роли. Библиотечные функции тоже обычно требуют только их. Хороший юзкейс для _t типов фиксированной разрядности - это описания различных структур данных для сериализации или протоколов передачи данных. В остальных случаях используют базовые типы.

archie
()
Ответ на: комментарий от intelfx

А твою метафору не понял) С++ не хочу трогать и 18 метровой палкой. Или твой пример и к Си относится?

makoven ★★★★★
() автор топика
Ответ на: комментарий от intelfx

Например, между C++03 и C++11 в гнутой реализации STL изменили определение std::list (в одном количество элементов хранится явно, в другом — каждый раз высчитывается за линию)

Это не в реализации изменили поведение, а в стандарте. У С++ с бинарной совсестимостью полный ахтунг.

mashina ★★★★★
()
Ответ на: комментарий от mashina

Да, в стандарте потребовали изменить алгоритмическую сложность size(), но как это сделать — ЕМНИП, implementation-defined.

intelfx ★★★★★
()
Ответ на: комментарий от intelfx

Здесь нет вариантов изменений с сохранением бинарной совместимости. Точно так же как нельзя оставить новый std::string совместимым со старым.

mashina ★★★★★
()
Ответ на: комментарий от makoven

Кстати, насчет _t. Есть смысл полностью отказываться от int, char, float.. в пользу всяких uint8_t?

Есть смысл, по мере необходимости и осознания зачем это нужно, кроме float - его заменить нечем. Например, заранее не известно какая разрядность будет у int, т.е. хватит ли её для нужд твоего кода или нет. Будет ли char знаковым типом или не будет, ну или хотя бы чтобы просто было понятно что ожидаешь - число и символ. Поисковик расскажет ещё больше юз. кейсов для stdint.h

mashina ★★★★★
()
Ответ на: комментарий от Gvidon

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

Я имеел ввиду стандарты на соглашение о вызовах и всё вот это прочее в линуксе. Если бы это можно было просто так сломать другими опциями или сменой версии компилятора/используемого стандарта языка, то было бы сложно вообще заставить линукс работать =).

Deleted
()
Ответ на: комментарий от intelfx

между C++03 и C++11 в гнутой реализации STL изменили определение std::list

Теперь стандарт просто обязывает возвращать длину списка за O(1), а раньше указаний не было, вот гнутые мартышки и считали «линию», и нигде больше такого идиотизма не было.

mix_mix ★★★★★
()
Ответ на: комментарий от intelfx

И от таких факапов стандарт не страхует

В стандарте и поменяли линейную сложность на константную, нет?

Kuzy ★★★
()
Ответ на: комментарий от mix_mix

вот гнутые мартышки и считали «линию», и нигде больше такого идиотизма не было.

Это наоборот самое корретное поведение для двусвязного списка, в новом стандарте всё испортили - нельзя делать splice всегда за O(1).

mashina ★★★★★
()
Ответ на: комментарий от mix_mix

Теперь стандарт просто обязывает возвращать длину списка за O(1)

Судя по написанному здесь, да, но на практике всё не так.

intelfx

max@ideapad max % cat test.cpp  
#include <ctime>
#include <iostream>
#include <list>

int main()
{
        std::list<int> a(1000000);
        clock_t c1 = clock();
        std::cout << a.size() << std::endl;
        clock_t c2 = clock();
        std::cout << c2-c1 << std::endl;

        std::list<int> b(10);
        clock_t c3 = clock();
        std::cout << b.size() << std::endl;
        clock_t c4 = clock();
        std::cout << c4-c3 << std::endl;

        return 0;
}
max@ideapad max % g++ test.cpp -o test -std=c++03 -Wall -Wextra -O3
max@ideapad max % ./test
1000000
4954
10
2
max@ideapad max % g++ test.cpp -o test -std=c++11 -Wall -Wextra -O3
max@ideapad max % ./test 
1000000
5473
10
2
max@ideapad max % clang++ test.cpp -o test -std=c++03 -Wall -Wextra -O3
max@ideapad max % ./test
1000000
5368
10
2
max@ideapad max % clang++ test.cpp -o test -std=c++11 -Wall -Wextra -O3
max@ideapad max % ./test                                               
1000000
4046
10
1
max@ideapad max % gcc --version
gcc (Gentoo 4.9.2 p1.0, pie-0.6.1) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
Это свободно распространяемое программное обеспечение. Условия копирования
приведены в исходных текстах. Без гарантии каких-либо качеств, включая 
коммерческую ценность и применимость для каких-либо целей.

max@ideapad max % clang --version
clang version 3.5.0 (tags/RELEASE_350/final)
Target: x86_64-pc-linux-gnu
Thread model: posix

Выходит, что работает за линию, что подтверждают и исходники: http://pastebin.com/ARV5Ecxf (если взглянуть на _List_iterator, то видно, что он последовательный; size() у списка возвращает std::distance(begin(), end())).

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

gentoo_root ★★★★★
()
Ответ на: комментарий от gentoo_root

Забавно. Значит, поменяли обратно (на неконформный вариант? WTF?). Или просто баг в какой-нибудь ifdef-щине.

Я точно помню, что однажды со мной этот факап случился. У меня было приложение, которое использовало C++11 и линковалось с libxml++ (которая собрана угадай кем и угадай с какими флагами, точнее без каких).

intelfx ★★★★★
()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от intelfx

Или просто баг в какой-нибудь ifdef-щине.

Ну я специально исходник прикрепил и даже прочитал его, там просто нигде нет места, где мог бы сохраняться размер. Просмотрел diff между 4.7.4, 4.8.3 и 4.9.2, там немногое отличается, вроде, тоже ничего такого нет.

gentoo_root ★★★★★
()
Ответ на: комментарий от intelfx

Или просто баг в какой-нибудь ifdef-щине.

Вероятно специально осталиви из-за проблем с совместимостью, точно так же как и std::string.

mashina ★★★★★
()
Ответ на: комментарий от mashina

splice не такая частая операция; потом, можно пойти на компромисс: при сплайсе сбрасывать длину в -1 и при запросе пересчитывать её.

mix_mix ★★★★★
()
Ответ на: комментарий от mix_mix

splice не такая частая операция

Это одна из уникальных фич из-за которой вообще может понадобиться использовать список.

можно пойти на компромисс: при сплайсе сбрасывать длину в -1 и при запросе пересчитывать её.

Нельзя, это нарушает новый стандарт и делает всё ещё хуже. Если в текушем splice работает за O(длина_вставляемного_участка), то в таком варианте это будет O(от_всего_спика), т.е. ещё больше тормозов в совсем неожиданных местах.

mashina ★★★★★
()
Ответ на: комментарий от gentoo_root

хмм

$ clang++ test.cpp -o test -std=c++03 -Wall -Wextra -O3
$ ./test
1000000
72
10
4
$ clang++ test.cpp -o test -std=c++11 -Wall -Wextra -O3
$ ./test
1000000
60
10
3
$ clang --version
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.0.0
Thread model: posix
mix_mix ★★★★★
()
Ответ на: комментарий от mashina

Нельзя, это нарушает новый стандарт и делает всё ещё хуже.

Почему? Всё как работало, так и будет, просто при сплайсе мы инвалидируем поле с длиной, и один раз она у нас (при следующем запросе длины) посчитается за линейное время, а так за константу. Т.е. тупо мемоизация с инвалидацией.

mix_mix ★★★★★
()
Последнее исправление: mix_mix (всего исправлений: 1)
Ответ на: комментарий от mix_mix

Почему?

Потому что. Что может быть непонятного в O(1) для size()? И вообще это константный метод. В коде где используют такой splice() вероятно не будут никогда дёргать size(), но тем не менее стандарт накладывает на реализации такие ограничения.

Нужно было делать два списка, один с size() за O(1), другой вообще без метода size() и с диапазонным splice()

mashina ★★★★★
()
Ответ на: комментарий от intelfx

Забавно. Значит, поменяли обратно (на неконформный вариант? WTF?).

Нет, просто gcc/libstdc++ не заявляли, что соответсвуют C++11 в полном объёме. Поэтому и не обязаны всё бросить и запилить в std::list поле с длиной.

ilammy ★★★
()
Ответ на: комментарий от Deleted

стандарты на соглашение о вызовах и всё вот это прочее в линуксе. Если бы это можно было просто так сломать другими опциями

Например для amd64 приложений в windows mingw умеет включать соглашение о вызовах как майкрософтовое, так и амдшное, которое используют все кроме MS. Видел этот прикол в amd64 реализации sbcl: там лисповый код закладывался на amd'шное соглашение о вызовах, так что сишный рантайм собирался с ним же.

kim-roader ★★
()
Ответ на: комментарий от mix_mix

splice не такая частая операция;

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

DarkEld3r ★★★★★
()
Ответ на: комментарий от makoven

Я везде читаю что MS вообще забил на сишный компилер и остановился на 89 стандарте. И агитирует всех переходить на C++ )

Вроде, С99 они всё-таки осилили (совсем недавно).

DarkEld3r ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.