» Вопросы по программированию на C/С++
Может быть в 01.c такое:
__declspec(dllexport) void foo(void)
{
}
лежит?
__declspec(dllexport) void foo(void)
{
}
лежит?
ne_viens
Это есть в bzlib.h
#ifndef __GNUC__
# define __DLL_IMPORT__ __declspec(dllimport)
# define __DLL_EXPORT__ __declspec(dllexport)
# else
# define __DLL_IMPORT__ __attribute__((dllimport)) extern
# define __DLL_EXPORT__ __attribute__((dllexport)) extern
# endif
И как это связано с построением статической библиотеки? Убрать __GNUC__?
Это есть в bzlib.h
#ifndef __GNUC__
# define __DLL_IMPORT__ __declspec(dllimport)
# define __DLL_EXPORT__ __declspec(dllexport)
# else
# define __DLL_IMPORT__ __attribute__((dllimport)) extern
# define __DLL_EXPORT__ __attribute__((dllexport)) extern
# endif
И как это связано с построением статической библиотеки? Убрать __GNUC__?
Какой-то странный bzlib.h
Скачай последний bzip c bzip.org/downloads.html (tarball).
Скачай последний bzip c bzip.org/downloads.html (tarball).
ne_viens
Скачено с порта на винду. последняя версия 1.0.5 дата файла 20.03.08 http://gnuwin32.sourceforge.net/packages/bzip2.htm Зачем повторять работу? Было всего лишь один варинг, работает ведь
Скачено с порта на винду. последняя версия 1.0.5 дата файла 20.03.08 http://gnuwin32.sourceforge.net/packages/bzip2.htm Зачем повторять работу? Было всего лишь один варинг, работает ведь
Добрый вечер. Нужен совет по весьма специфическому вопросу. Пишу программу для снятия данных с прибора. Язык C++, компилятор GCC 3.4.2 (MinGW). Использую DLL фирмы-производителя прибора. Описание есть, то есть не угадываю.
При компиляции в режиме отладки работает программа без проблем. Но при компиляции в режиме Release программа вылетает с ошибкой. Тип ошибки либо Segmentation fault, либо Illegal instruction.
[more=далее]Выяснил, что проблема появляется при включении режима оптимизации -O1 или -O2, который подставляет код inline функций вызова внешней функции DLL прямо в код программы. У одной такой функции убрал inline, в конкретном месте проблема исчезла.
Отладчиком выяснил, что вылет происходит после return'а той функции, в которую подставили код inline функции. В проблемном месте return возвращает управление не в ту, функцию, которая вызвала текущую, а создаётся впечатление, что в случайное место. Складывается такое ощущение, что при вызове функции внешней DLL портится какой-то регистр.
Код:
inline int AVS_GetList (unsigned int a_ListSize, unsigned int* a_pRequiredSize,
struct AvsIdentityType* a_pList)
{
if (!dll.AVS_GetList) return ERR_INVALID_DLL_VERSION;
const int res = dll.AVS_GetList (a_ListSize, a_pRequiredSize, a_pList);
//dll - структура с указателями на функции DLL
return res;
}
При компиляции в режиме отладки работает программа без проблем. Но при компиляции в режиме Release программа вылетает с ошибкой. Тип ошибки либо Segmentation fault, либо Illegal instruction.
[more=далее]Выяснил, что проблема появляется при включении режима оптимизации -O1 или -O2, который подставляет код inline функций вызова внешней функции DLL прямо в код программы. У одной такой функции убрал inline, в конкретном месте проблема исчезла.
Отладчиком выяснил, что вылет происходит после return'а той функции, в которую подставили код inline функции. В проблемном месте return возвращает управление не в ту, функцию, которая вызвала текущую, а создаётся впечатление, что в случайное место. Складывается такое ощущение, что при вызове функции внешней DLL портится какой-то регистр.
Код:
inline int AVS_GetList (unsigned int a_ListSize, unsigned int* a_pRequiredSize,
struct AvsIdentityType* a_pList)
{
if (!dll.AVS_GetList) return ERR_INVALID_DLL_VERSION;
const int res = dll.AVS_GetList (a_ListSize, a_pRequiredSize, a_pList);
//dll - структура с указателями на функции DLL
return res;
}
nick7inc
Цитата:
ESP портится, надо полагать. Такое может быть, если тип вызова не соответствует типу функции. Если, скажем, скомпилирована функция как __cdecl, а вызывается как __stdcall. Или наоборот. Потому что __cdecl и __stdcall по-разному очищают стек от переданных в функцию параметров.
Цитата:
Отладчиком выяснил, что вылет происходит после return'а той функции, в которую подставили код inline функции. В проблемном месте return возвращает управление не в ту, функцию, которая вызвала текущую, а создаётся впечатление, что в случайное место. Складывается такое ощущение, что при вызове функции внешней DLL портится какой-то регистр.
ESP портится, надо полагать. Такое может быть, если тип вызова не соответствует типу функции. Если, скажем, скомпилирована функция как __cdecl, а вызывается как __stdcall. Или наоборот. Потому что __cdecl и __stdcall по-разному очищают стек от переданных в функцию параметров.
Abs62
Цитата:
Вполне может быть. В SDK для прибора, которым я пользуюсь, нет набора .h и .lib для конкретно моей среды разработки. У меня GCC, а там есть только для Borland C++Builder 5, Codegear C++Builder 2009 и vcpp2008 (для С++). Поэтому мне приходится загружать функции из DLL вручную при помощи LoadLibrary() и GetProcAddress(). Прототип функций я взял из заголовочного файла Borland C++Builder 5:
Код: DLL_API int __stdcall AVS_GetList
( unsigned int a_ListSize, unsigned int* a_pRequiredSize, AvsIdentityType* a_pList);
Цитата:
тип вызова не соответствует типу функции
Вполне может быть. В SDK для прибора, которым я пользуюсь, нет набора .h и .lib для конкретно моей среды разработки. У меня GCC, а там есть только для Borland C++Builder 5, Codegear C++Builder 2009 и vcpp2008 (для С++). Поэтому мне приходится загружать функции из DLL вручную при помощи LoadLibrary() и GetProcAddress(). Прототип функций я взял из заголовочного файла Borland C++Builder 5:
Код: DLL_API int __stdcall AVS_GetList
( unsigned int a_ListSize, unsigned int* a_pRequiredSize, AvsIdentityType* a_pList);
.lib можно из .h сделать.
Тогда отпадёт надобность в GetProcAddress(LoadLibrary(""), "");
Тогда отпадёт надобность в GetProcAddress(LoadLibrary(""), "");
ne_viens
Цитата:
Да мне не трудно через GetProcAddress(). Замена __stdcall на __cdecl проблему не решила. Я не уверен в прототипе функций, описанных в заголовке для Borland C++Builder 5. Всё, что у меня сейчас есть, это DLL, описание в PDF (где ни о __stdcall, ни о __cdecl ни слова не сказано) и пример-исходник программы для Borland C++Builder 5, для коего есть LIB, но которым я не могу воспользоваться..
Цитата:
.lib можно из .h сделать.
Да мне не трудно через GetProcAddress(). Замена __stdcall на __cdecl проблему не решила. Я не уверен в прототипе функций, описанных в заголовке для Borland C++Builder 5. Всё, что у меня сейчас есть, это DLL, описание в PDF (где ни о __stdcall, ни о __cdecl ни слова не сказано) и пример-исходник программы для Borland C++Builder 5, для коего есть LIB, но которым я не могу воспользоваться..
Из борландовского .h явно видно, что ф-я __stdcall.
Если ее вызывать по __cdecl соглашению, ошибка будет в любом случае- оптимизирован код или нет.
Если ее вызывать по __cdecl соглашению, ошибка будет в любом случае- оптимизирован код или нет.
ne_viens
Цитата:
Без оптимизации не проявляется, возможно из-за обёрточной функции.
Цитата:
ошибка будет в любом случае- оптимизирован код или нет.
Без оптимизации не проявляется, возможно из-за обёрточной функции.
Ну незнаю, у меня и без -О и с -О работает:
Код: //gcc -Wall -O3 err.c -o err.exe
#include <windows.h>
#include <stdlib.h>
#define ERR_INVALID_DLL_VERSION -8
struct AvsIdentityType {int i, j;};
typedef int (__stdcall *_AVS_GetList)(unsigned int, unsigned int*, struct AvsIdentityType*);
typedef struct {
char c;
int i;
_AVS_GetList AVS_GetList;
// other functions follow
} PACK;
PACK dll;
/////////////////////////////////////////////////////////////////////////////////////////////
inline int AVS_GetList(unsigned int a_ListSize, unsigned int* a_pRequiredSize,
struct AvsIdentityType* a_pList)
{
if(!dll.AVS_GetList) return ERR_INVALID_DLL_VERSION;
const int res = dll.AVS_GetList (a_ListSize, a_pRequiredSize, a_pList);
return res;
}
/////////////////////////////////////////////////////////////////////////////////////////////
int main()
{
unsigned int i;
int j;
struct AvsIdentityType ait;
dll.AVS_GetList = GetProcAddress(LoadLibrary("avslib.dll"), "AVS_GetList");
j = dll.AVS_GetList(1, &i, &ait);
return j;
}
Код: //gcc -Wall -O3 err.c -o err.exe
#include <windows.h>
#include <stdlib.h>
#define ERR_INVALID_DLL_VERSION -8
struct AvsIdentityType {int i, j;};
typedef int (__stdcall *_AVS_GetList)(unsigned int, unsigned int*, struct AvsIdentityType*);
typedef struct {
char c;
int i;
_AVS_GetList AVS_GetList;
// other functions follow
} PACK;
PACK dll;
/////////////////////////////////////////////////////////////////////////////////////////////
inline int AVS_GetList(unsigned int a_ListSize, unsigned int* a_pRequiredSize,
struct AvsIdentityType* a_pList)
{
if(!dll.AVS_GetList) return ERR_INVALID_DLL_VERSION;
const int res = dll.AVS_GetList (a_ListSize, a_pRequiredSize, a_pList);
return res;
}
/////////////////////////////////////////////////////////////////////////////////////////////
int main()
{
unsigned int i;
int j;
struct AvsIdentityType ait;
dll.AVS_GetList = GetProcAddress(LoadLibrary("avslib.dll"), "AVS_GetList");
j = dll.AVS_GetList(1, &i, &ait);
return j;
}
nick7inc
Цитата:
Угу, судя по дисассемблированному коду, оператор "mov %ebp,%esp" восстанавливает ESP, что бы с ним внутри функции ни происходило.
Думаю, тут надо смотреть в отладчике, пошагово проходя дисассемблированный код. После всех манипуляций с передачей параметров и вызова функции значение ESP должно вернуться к тому, что было до того. Если этого не происходит, надо разбираться, что именно тут не так.
Кстати, тут же можно и сразу посмотреть, какого типа на самом деле вызываемая функция. Если после возврата из "call *%edx" ESP меняется, это stdcall, если нет - cdecl (это касается функций с параметрами, если параметров нет, ESP в любом варианте не поменяется).
Цитата:
Без оптимизации не проявляется, возможно из-за обёрточной функции.
Угу, судя по дисассемблированному коду, оператор "mov %ebp,%esp" восстанавливает ESP, что бы с ним внутри функции ни происходило.
Думаю, тут надо смотреть в отладчике, пошагово проходя дисассемблированный код. После всех манипуляций с передачей параметров и вызова функции значение ESP должно вернуться к тому, что было до того. Если этого не происходит, надо разбираться, что именно тут не так.
Кстати, тут же можно и сразу посмотреть, какого типа на самом деле вызываемая функция. Если после возврата из "call *%edx" ESP меняется, это stdcall, если нет - cdecl (это касается функций с параметрами, если параметров нет, ESP в любом варианте не поменяется).
Abs62, ne_viens
Спасибо большое за наставления. Постараюсь позже поэкспериментировать с ассемблером (посмотрю за ESP) (сейчас студент грузит). В качестве маркеров начала кода вызова функции вставлю asm("nop") перед и после вызова функции.
P.S. Abs62 Значение ESP должно меняться, когда начинается подготовка параметров для передачи функции?
Спасибо большое за наставления. Постараюсь позже поэкспериментировать с ассемблером (посмотрю за ESP) (сейчас студент грузит). В качестве маркеров начала кода вызова функции вставлю asm("nop") перед и после вызова функции.
P.S. Abs62 Значение ESP должно меняться, когда начинается подготовка параметров для передачи функции?
nick7inc
Цитата:
А это как разработчики компилятора реализовали, так и будет. В классическом варианте да, параметры загоняются в стек командой "push". А MinGW 4.8.1, к примеру (на других версиях не смотрел), пользуется "mov", не меняя значения ESP.
Цитата:
P.S. Abs62 Значение ESP должно меняться, когда начинается подготовка параметров для передачи функции?
А это как разработчики компилятора реализовали, так и будет. В классическом варианте да, параметры загоняются в стек командой "push". А MinGW 4.8.1, к примеру (на других версиях не смотрел), пользуется "mov", не меняя значения ESP.
Цитата:
...Значение ESP должно меняться, когда начинается подготовка параметров для передачи функции?
Для MCVC 32бит меняется, так как каждый аргумент передаётся инструкцией push, но для GCC обычно нет, так как GCC в начале каждой подпрограммы выделяет место для аргументов вложенных функций, а аргументам присваивает значения с
mov [esp], arg0
mov [esp+4], arg1
mov [esp+8], arg2
itd.
а как же фастколлы через регистры, если попросить?
Там страшный бардак между компилерами/OSями, в каком регистре какой аргумент.
да надо самому всё жёстко строго описывать, без всяких дефолтов...
Abs62
Цитата:
Оптимизация отключена, функция не inline. [more=Код]
Код: 00439C46 push %ebp
00439C47 mov %esp,%ebp
00439C49 sub $0x18,%esp
00439C4C mov 0x8(%ebp),%eax
00439C4F cmpl $0x0,0x10(%eax)
00439C53 jne 0x439c5e <Avantes_IO::Avantes::AVS_GetList(unsigned int, unsigned int*, Avantes_IO::AvsIdentityType*)+24>
00439C55 movl $0xffffffee,-0x8(%ebp)
00439C5C jmp 0x439c83 <Avantes_IO::Avantes::AVS_GetList(unsigned int, unsigned int*, Avantes_IO::AvsIdentityType*)+61>
00439C5E mov 0x8(%ebp),%edx
00439C61 mov 0x14(%ebp),%eax
00439C64 mov %eax,0x8(%esp)
00439C68 mov 0x10(%ebp),%eax
00439C6B mov %eax,0x4(%esp)
00439C6F mov 0xc(%ebp),%eax
00439C72 mov %eax,(%esp)
00439C75 mov 0x10(%edx),%eax
00439C78 call *%eax
00439C7A mov %eax,-0x4(%ebp)
00439C7D mov -0x4(%ebp),%eax
00439C80 mov %eax,-0x8(%ebp)
00439C83 mov -0x8(%ebp),%eax
00439C86 leave
00439C87 ret
Цитата:
смотреть в отладчике, пошагово проходя дисассемблированный код
Оптимизация отключена, функция не inline. [more=Код]
Код: 00439C46 push %ebp
00439C47 mov %esp,%ebp
00439C49 sub $0x18,%esp
00439C4C mov 0x8(%ebp),%eax
00439C4F cmpl $0x0,0x10(%eax)
00439C53 jne 0x439c5e <Avantes_IO::Avantes::AVS_GetList(unsigned int, unsigned int*, Avantes_IO::AvsIdentityType*)+24>
00439C55 movl $0xffffffee,-0x8(%ebp)
00439C5C jmp 0x439c83 <Avantes_IO::Avantes::AVS_GetList(unsigned int, unsigned int*, Avantes_IO::AvsIdentityType*)+61>
00439C5E mov 0x8(%ebp),%edx
00439C61 mov 0x14(%ebp),%eax
00439C64 mov %eax,0x8(%esp)
00439C68 mov 0x10(%ebp),%eax
00439C6B mov %eax,0x4(%esp)
00439C6F mov 0xc(%ebp),%eax
00439C72 mov %eax,(%esp)
00439C75 mov 0x10(%edx),%eax
00439C78 call *%eax
00439C7A mov %eax,-0x4(%ebp)
00439C7D mov -0x4(%ebp),%eax
00439C80 mov %eax,-0x8(%ebp)
00439C83 mov -0x8(%ebp),%eax
00439C86 leave
00439C87 ret
nick7inc
Цитата:
Угу, функция stdcall. А вот компилятор вызывает её как cdecl, иначе после "call *%eax" стоял бы код "sub $0xc,%esp", возвращающий ESP в нужное положение. Проверьте объявление указателя на эту функцию.
Цитата:
leave возвращает ESP в состояние, в каком он был перед "push %ebp".
Цитата:
До 00439C78 значение ESP сохраняется. После call оно становиться (ESP=0x23fb8C)
Угу, функция stdcall. А вот компилятор вызывает её как cdecl, иначе после "call *%eax" стоял бы код "sub $0xc,%esp", возвращающий ESP в нужное положение. Проверьте объявление указателя на эту функцию.
Цитата:
после leave оно стало (ESP=0x23fb9C).
leave возвращает ESP в состояние, в каком он был перед "push %ebp".
Abs62
Кажется проблема решена (см. предыдущее сообщение). В объявлении typedef была ошибка, из-за чего компилер не считал эту функцию stdcall (не туда поставил ключевое слово).
Всем спасибо!
Добавлено:
Цитата:
Понял.
Кажется проблема решена (см. предыдущее сообщение). В объявлении typedef была ошибка, из-за чего компилер не считал эту функцию stdcall (не туда поставил ключевое слово).
Всем спасибо!
Добавлено:
Цитата:
leave возвращает ESP в состояние, в каком он был перед "push %ebp".
Понял.
Как получить беззнаковое значение двух байт?
Для одного байта
char *source;
unsigned char *msg;
msg=(unsigned char*) malloc(2);
msg = reinterpret_cast<unsigned char*>(source+19);
надо unsigned short из куска source
ЗЫ ne_viens С bzip2 оказывается подсовывал не ту б-ку. Надо libbz2.lib
Для одного байта
char *source;
unsigned char *msg;
msg=(unsigned char*) malloc(2);
msg = reinterpret_cast<unsigned char*>(source+19);
надо unsigned short из куска source
ЗЫ ne_viens С bzip2 оказывается подсовывал не ту б-ку. Надо libbz2.lib
kkuuhhaa
Вы указатель (адрес) присваиваете в качестве значения переменной.
Вы указатель (адрес) присваиваете в качестве значения переменной.
nick7inc
Ну исправил, про другое ж вопрос.
Ну исправил, про другое ж вопрос.
kkuuhhaa
Цитата:
Зачем?
Цитата:
Дык, кто мешает кастовать указатель не к unsigned char*, а к unsigned short*?
Цитата:
msg=(unsigned char*) malloc(2);
Зачем?
Цитата:
надо unsigned short из куска source
Дык, кто мешает кастовать указатель не к unsigned char*, а к unsigned short*?
char *source;
unsigned short val;
val = *((unsigned short*)(source+19));
не?
unsigned short val;
val = *((unsigned short*)(source+19));
не?
Abs62
suslovp
спасибо, оба варианта работают.
suslovp
спасибо, оба варианта работают.
Всем доброго времени суток. Вот у же не первый день сижу и не одну книгу почитал. Не буду говорить, что нет того что надо. Просто может я не понимаю.
У меня есть выпадающее меню ComboBox в нем три строчки, при выборе одной из строчек в окне Edit должно автоматически вводится числовое значение, которое как-то надо присвоит конкретной строчке! Как это сделать!
У меня есть выпадающее меню ComboBox в нем три строчки, при выборе одной из строчек в окне Edit должно автоматически вводится числовое значение, которое как-то надо присвоит конкретной строчке! Как это сделать!
Страницы: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
Предыдущая тема: не знаю как назвать тему :-)
Форум Ru-Board.club — поднят 15-09-2016 числа. Цель - сохранить наследие старого Ru-Board, истории становления российского интернета. Сделано для людей.