У меня есть функция C в статической библиотеке, назовем ее A, со следующим интерфейсом:
int A(unsigned int a, unsigned long long b, unsigned int *y, unsigned char *z);
Эта функция изменит значение y и z (это точно). Я использую его из динамической библиотеки C++, используя extern «C».
Вот что меня ошеломило:
Я думаю, что приведенные выше пункты показывают, что это не глупая ошибка с объявлением моих переменных.
Я явно застрял, и я не могу изменить библиотеку C. Вы хоть понимаете, в чем может быть проблема? Я думал о проблеме с интерфейсом C / C++, в зависимости от того, как интерпретируется char *.
Обновлено: я наконец выяснил, в чем проблема. Смотрите ниже мой ответ.
Мне любопытно, почему вы используете английский, чтобы описать в точности то, что вы можете отобразить, показывая код. У нас есть только ваше слово, что вы все настраиваете правильно. Но если вы покажете нам код, мы узнаем, правильно ли вы это делаете.
Что ж, я думал, что код слишком сложен, чтобы поместить его сюда напрямую. Но, вы правы, в следующий раз я подумаю о том, чтобы дать хотя бы упрощенный код, если это имеет смысл.





Насколько мне известно, long long не является частью стандартного C++, возможно, это источник вашей проблемы.
В вашей программе на C++ заявлен ли прототип с extern "C"?
Не знаю. Попробуйте выполнить отладку в A и посмотрите, что произойдет (предупреждение кода сборки!)
Вы правы насчет «предупреждения кода сборки», библиотека C не содержит символов ... Не уверен, что смогу это понять.
Может быть, вы можете обернуть исходную функцию в библиотеку C, которую вы вызываете из своей библиотеки C++?
Основываясь на ваших пунктах 2 и 3, похоже, что это может сработать.
Если это не так, это дает вам еще одну точку отладки, чтобы найти больше подсказок - посмотрите, в какой из ваших библиотек сначала возникает ошибка, и проверьте, почему 2 и 3 работают, но это не так - какова минимальная разница?
Вы также можете попробовать проверить стек, который создается вызовом вашей функции в каждом случае, чтобы проверить, есть ли здесь разница, учитывая разные соглашения о вызовах.
Шаг 1. Сравните указатели y и z, переданные со стороны C++, с указателями, полученными функцией C.
P.S. Я не хочу казаться очевидным, просто перепроверьте здесь. Я полагаю, когда вы говорите, что z изменяется нормально при вызове из двоичного файла C, вы имеете в виду, что данные, на которые указывает z, изменяются просто отлично. Сами указатели y и z передаются по значению, поэтому вы не можете изменить указатели.
Да, когда я говорю, что Z изменен, я имею в виду, что данные, на которые указывает z, изменены. Я посмотрю на указатели с обеих сторон. Благодарность
Похоже, разница между тем, как ваша библиотека C и компилятор C++ работают с длинные лонги. Я предполагаю, что библиотека C, вероятно, является стандартом до C89 и фактически обрабатывает 64-битный долго долго как 32-битный. Ваша библиотека C++ обрабатывает его правильно и размещает 64 бита в стеке вызовов и, следовательно, искажает y и z. Возможно, попробуйте вызвать функцию через * int A (unsigned int a, unsigned long b, unsigned int * y, unsigned char z) и посмотрите, что вы получите.
Просто мысль.
Предполагая, что приведенное выше верно, без предложенной модификации функция C будет видеть y = 0 (на архитектурах с прямым порядком байтов) и z как указывающий на то, куда указывает C++ y.
да. Учитывая, что y является указателем, он становится архитектурно-зависимым. Я предполагаю, что OP использует 32-битную систему, так что y = 0 можно было бы лучше подумать как y = NULL.
Я попробовал то, что вы предложили (звонок с беззнаковым длинным), но это не помогло. Александр: y изменяется с помощью A (), а z просто указывает на то же значение, что и до вызова.
Хорошо, я вполне мог ошибаться, так как это было всего лишь предположением. Попробуйте проверить sizeof (unsigned long long) в обоих компиляторах. В обоих случаях должно быть 8 байтов. Если нет, то это ваша проблема и вам нужен новый прототип, иначе это что-то другое.
Это один из тех вопросов, где нет ничего очевидного неправильного в том, что вы описали, но все работает не так, как вы ожидаете.
Я думаю, вам стоит редактировать свой пост, чтобы дать намного больше информации, чтобы получить некоторые разумные ответы. В частности, начнем с: -
Если вы не ошибаетесь в том, что A всегда изменяет данные, на которые указывает Z, единственной вероятной причиной вашей проблемы является несовместимость между соглашениями о передаче параметров. Проблема «долго-долгого» может быть намеком на то, что все обстоит не так, как кажется.
В крайнем случае вы можете сравнить дизассемблированный вызывающий код C++ (который, по вашему мнению, не работает) и вызывающий код C (который, по вашему мнению, прошел успешно), или выполнить инструкции ЦП с помощью отладчика (да, действительно - вы узнаете хорошее умение а так же решение проблемы)
Еще одна дикая догадка: вы уверены, что связываете правильный экземпляр функции в вашей библиотеке C? Может быть, в ваших библиотеках доступно несколько таких функций? В C компоновщик не заботится о типе возвращаемого значения или списке параметров при решении, как разрешить функцию - важно только имя. Итак, если у вас есть несколько функций с одинаковым именем ...
Вы можете программно проверить идентичность функции. Создайте библиотеку C, которая вызывает вашу функцию A с некоторыми тестовыми параметрами, которая работает нормально и печатает указатель на функцию A. Свяжите библиотеку с вашим приложением C++. Затем распечатайте указатель на исходную функцию A, как видно из кода C++, и сравните указатель с указателем, который видит ваша библиотека C при вызове в том же процессе.
Опять же, очевидный, но кто знает ... Вы уверены, что вызываемая функция C не имеет состояния, то есть ее вывод зависит только от ее входных данных? Если функция не имеет состояния, возможно, «скрытое» состояние отвечает за различное поведение (не изменение данных, на которые указывает z) функции при вызове из вашего приложения C++.
Прежде всего, я всем очень благодарен за вашу помощь. Благодаря многочисленным идеям и подсказкам, которые вы мне дали, я наконец смог решить эту проблему. Ваши советы помогли мне усомниться в том, что я считал само собой разумеющимся.
Краткий ответ на мою проблему: проблема заключалась в том, что моя библиотека C++ использовала старую версию библиотеки C. В этой старой версии пропущен 4-й аргумент. Как следствие, четвертый аргумент, очевидно, не изменился.
Мне немного стыдно теперь, когда я понял, что это проблема. Однако меня сбило с толку то, что мой код компилировался нормально. Это было связано с тем, что библиотека C++ скомпилирована с использованием правильной версии библиотеки C lib, но во время выполнения она использовала старую версию, статически связанную с другой библиотекой, которую я использовал.
C++ Lib (M) ---> dyn C++ lib (N) ---> C lib (P) v.1.0
|
------> C lib (P) v.1.1
(N) - это динамическая библиотека, которая статически связана с (P) версии 1.0. Компилятор принял вызов от (M) к функции с 4 аргументами, потому что я связался с (P) версией 1.1, но во время выполнения он использовал старую версию (P).
Не стесняйтесь редактировать этот ответ или вопрос или попросить меня сделать это.
Спасибо. Вы очень помогли мне с вашими ответами (спрашивая, связывал ли я правильный экземпляр функции в библиотеке C для каждого экземпляра, а также другие). Ваше здоровье !
Бинарный файл C, о котором вы говорите в пункте 2, компилировался ли он вами недавно? Если нет, что произойдет, если вы перекомпилируете двоичный файл? Мне интересно, действительно ли функция внутри библиотеки C делает то, что должна делать.