Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Классы в библиотеках 
:(
    Опции темы
EvgeniyK77
Дата 15.8.2012, 08:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 19.8.2006

Репутация: нет
Всего: нет



Подскажите, пожалуйста, как корректно разместить класс в статической библиотеке (.a)?

Поясню суть. Есть некоторый класс, который я скомпилировал в Linux с помощью mingw. Полученную библиотеку и заголовочный файл дал другому человеку, который её использовал в своей программе. Всё было здорово. Всё чудно линковалось и работало... До поры до времени. После очередного обновления mingw (у него) программа стала падать в одном из моих методов. При этом линковщик не ругался. После пересборки моей библиотеки на его машине падения прекратились. Стал разбираться. Оказалось, что mingw вдруг решил для методов поменять порядок аргументов (this поместил в другое место)! Я, конечно, понимаю, что классы в библиотеках - это не очень хорошо, т.к. разные компиляторы по-разному генерят имена для методов, и библиотека, собранная одним компилятором, может не подлинковаться другим. Но компилятор ведь один! Да и линковка прошла успешно...

Быть может, есть какие-то стандартные способы, типа extern "C"?

Если интересно, вот тест (библ. собрана на Fedora 14, а программа - на Fedora 17):
Код

// TestClassLib.hpp
#ifndef TEST_CLASS_LIB_HPP
#define TEST_CLASS_LIB_HPP

class TestClass1 {
public:
    void Fun1(int a0, int a1, int a2, int a3);
};

#endif

Код

// TestClassLib.cpp
#include <stdio.h>
#include "TestClassLib.hpp"

void TestClass1::Fun1(int a0, int a1, int a2, int a3) {
    printf("%d %d %d %d (this=%d)\n", a0, a1, a2, a3, (int)this); fflush(stdout);
}

Код

// Тестовая программа
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "TestClassLib.hpp"

int main() {
    TestClass1 zzz;
    zzz.Fun1(10,11,12,13);
    return 0;
}

Программы выводит:
Код

11 12 13 2009226388 (this=10)

PM MAIL   Вверх
Cheloveck
Дата 15.8.2012, 10:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1578
Регистрация: 26.7.2008
Где: Тула

Репутация: 3
Всего: 32



Цитата(EvgeniyK77 @  15.8.2012,  09:01 Найти цитируемый пост)
this поместил в другое место

this передаётся в регистре ECX, это конвенция thiscall и никаких вольностей компилятор тут позволять себе не должен. Порядок аргументов тоже определён thiscall. Проблема где-то в другом месте.


Это сообщение отредактировал(а) Cheloveck - 15.8.2012, 10:11


--------------------
user posted image
PM Jabber   Вверх
korian
Дата 15.8.2012, 11:21 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 651
Регистрация: 8.3.2008
Где: Украина, Харьков

Репутация: 3
Всего: 17



Цитата(Cheloveck @  15.8.2012,  09:11 Найти цитируемый пост)
this передаётся в регистре ECX, это конвенция thiscall 

Это всего лишь соглашение, а не стандарт. И никто его поддерживать не обязан.
Да и что делать на системах, в которых регистра ECX изначально не было?
http://www.ownedcore.com/forums/world-of-w...in32-mingw.html

EvgeniyK77
Я точно не знаю, но поидее надо или перекомпиливать все одним компилятором или использовать только cdecl С-функции, т.е. никакого C++ наверху торчать не должно.

PM   Вверх
EvgeniyK77
Дата 17.8.2012, 09:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 19.8.2006

Репутация: нет
Всего: нет



Спасибо!

Стал разбираться с модификаторами и узнал, что в mingw 4.7 умолчальный модификатор методов изменился на __thiscall. В 4.5 такого вообще нет.
Если у метода явно поставить __fastcall, __stdcall или __cdecl, то всё работает!

Какой из этих модификаторов предпочтительнее?

PM MAIL   Вверх
leniviy
Дата 17.8.2012, 09:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 552
Регистрация: 8.2.2003
Где: Спб

Репутация: 1
Всего: 5



Цитата(EvgeniyK77 @  15.8.2012,  08:01 Найти цитируемый пост)
Если интересно, вот тест

не мог бы ты приаттачить 2 версии тестовой либы? Одну собранную на старом MinGW, другую - на новом.
Естественно, с -g -O0.

Цитата(EvgeniyK77 @  15.8.2012,  08:01 Найти цитируемый пост)
При этом линковщик не ругался.


По идее, у методов __cdecl и __thiscall должна быть разная сигнатура. Visual C++:
Код

"public: void __cdecl    TestClass::nnn(void)" (?nnn@TestClass@@QAAXXZ)
"public: void __thiscall TestClass::nnn(void)" (?nnn@TestClass@@QAEXXZ)

@@QAAXXZ vs @@QAEXXZ

То есть, программа не должна была компилироваться.

Это сообщение отредактировал(а) leniviy - 17.8.2012, 09:53
PM MAIL   Вверх
EvgeniyK77
Дата 17.8.2012, 10:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 19.8.2006

Репутация: нет
Всего: нет



Сделано!

Присоединённый файл ( Кол-во скачиваний: 4 )
Присоединённый файл  test.tgz 2,06 Kb
PM MAIL   Вверх
leniviy
Дата 17.8.2012, 10:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 552
Регистрация: 8.2.2003
Где: Спб

Репутация: 1
Всего: 5



спасибо. Похоже, что в mingw gcc сигнатура одинаковая.

Цитата(EvgeniyK77 @  17.8.2012,  09:10 Найти цитируемый пост)
Какой из этих модификаторов предпочтительнее?

Идеального нет. Я бы использовал __thiscall, так как он быстрее:

Код

#if defined(_WIN32) && defined(__MINGW32__)
  #define MYCALL __thiscall
#else
  #define MYCALL
#endif


А на старом компиляторе пускай не собирается. Кто умеет ставить MinGW, сможет поставить и новый MinGW
PM MAIL   Вверх
Randajad
Дата 17.8.2012, 13:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 295
Регистрация: 15.3.2012

Репутация: 8
Всего: 8



Кто сказал, что классы в библиотеках - плохая идея? Не говорите таких глупостей. smile
GCC версии < 4.7 передает this через стэк. GCC версии >= 4.7 передает this через ecx на x86 платформах. Это сделано для обеспечения совместимости с MSVC либами. Другого не дано. smile На этом обратная совместимость заканчивается. Кстати, LTO библиотеки не совместимы даже с разными билдами компилятора в пределах одной версии.

Не нужно указывать никаких extern/__thiscall в статических либах. Зачем? Просто используйте оба компилятор или выше 4.6, или равный и ниже ему.

Добавлено через 4 минуты и 9 секунд
To leniviy:
Вопрос насчет быстроты __thiscall спорный. Может, тогда fastcall еще быстрее? Однако, его никто не использует. 

Это сообщение отредактировал(а) Randajad - 17.8.2012, 13:06
PM MAIL   Вверх
leniviy
Дата 17.8.2012, 13:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 552
Регистрация: 8.2.2003
Где: Спб

Репутация: 1
Всего: 5



Цитата(Randajad @  17.8.2012,  13:04 Найти цитируемый пост)
Не нужно указывать никаких extern/__thiscall в статических либах. Зачем?

Это значит, оставить всё как есть.
Лучше пускай программа валится на сборке, чем при работе. А для этого нужно, чтобы несовместимую библиотеку нельзя было подключить.

До совместимости с MSVC далеко: имена C++ по-разному декорируются.

Цитата(Randajad @  17.8.2012,  13:04 Найти цитируемый пост)
опрос насчет быстроты __thiscall спорный. Может, тогда fastcall еще быстрее? Однако, его никто не использует.

Здесь выбор только между двумя вариантами: cdecl и thiscall.
PM MAIL   Вверх
Randajad
Дата 17.8.2012, 14:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 295
Регистрация: 15.3.2012

Репутация: 8
Всего: 8



Это все хорошо, но этот шаг сделан именно ради улучшения совместимости с MSVC. Такие "валы" видны сразу же при первом запуске. Виноват человек и пихать везде MYCALL - не решение проблемы.
Почему между двумя? Fastcall поддерживает классы тоже.

Это сообщение отредактировал(а) Randajad - 17.8.2012, 14:45
PM MAIL   Вверх
EvgeniyK77
Дата 20.8.2012, 07:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 19.8.2006

Репутация: нет
Всего: нет



Цитата

Такие "валы" видны сразу же при первом запуске.
Видны... Это да. Но причина очень даже не очевидна. Программа большая, и мы, пока не пересобрали либу, думали, что поломалось где-то в другом месте, а проявилось здесь.
На различия компиляторов я не думал, т.к. считал, что либа, в случае чего, просто не подлинкуется.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0530 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.