Почему мой параметр, переданный по ссылке, не изменяется в функции?

У меня есть функция C в статической библиотеке, назовем ее A, со следующим интерфейсом:

int A(unsigned int a, unsigned long long b, unsigned int *y, unsigned char *z);

Эта функция изменит значение y и z (это точно). Я использую его из динамической библиотеки C++, используя extern «C».

Вот что меня ошеломило:

  • y установлен правильно, z не изменяется. Я имею в виду, что если оба инициализируются (заостренным) значением 666, значение, указанное y, изменится после вызова, но не значение, указанное z (все еще 666).
  • при вызове из двоичного кода C эта функция работает без проблем (значение обозначенный z изменен).
  • если я создаю фиктивную библиотеку C с функцией, имеющей тот же прототип, и использую ее из своей динамической библиотеки C++, она работает очень хорошо. Если я повторно использую те же переменные для вызова A (..), я получаю тот же результат, что и раньше, z не изменяется.

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

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

Обновлено: я наконец выяснил, в чем проблема. Смотрите ниже мой ответ.

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

Alexander 29.09.2008 16:13

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

Martin York 29.09.2008 21:06

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

Barth 29.09.2008 23:21
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
689
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

Насколько мне известно, long long не является частью стандартного C++, возможно, это источник вашей проблемы.

В вашей программе на C++ заявлен ли прототип с extern "C"?

Не знаю. Попробуйте выполнить отладку в A и посмотрите, что произойдет (предупреждение кода сборки!)

Вы правы насчет «предупреждения кода сборки», библиотека C не содержит символов ... Не уверен, что смогу это понять.

Barth 29.09.2008 15:47

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

Основываясь на ваших пунктах 2 и 3, похоже, что это может сработать.

Если это не так, это дает вам еще одну точку отладки, чтобы найти больше подсказок - посмотрите, в какой из ваших библиотек сначала возникает ошибка, и проверьте, почему 2 и 3 работают, но это не так - какова минимальная разница?

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

Шаг 1. Сравните указатели y и z, переданные со стороны C++, с указателями, полученными функцией C.

P.S. Я не хочу казаться очевидным, просто перепроверьте здесь. Я полагаю, когда вы говорите, что z изменяется нормально при вызове из двоичного файла C, вы имеете в виду, что данные, на которые указывает z, изменяются просто отлично. Сами указатели y и z передаются по значению, поэтому вы не можете изменить указатели.

Да, когда я говорю, что Z изменен, я имею в виду, что данные, на которые указывает z, изменены. Я посмотрю на указатели с обеих сторон. Благодарность

Barth 29.09.2008 14:04

Похоже, разница между тем, как ваша библиотека 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.

Alexander 29.09.2008 14:03

да. Учитывая, что y является указателем, он становится архитектурно-зависимым. Я предполагаю, что OP использует 32-битную систему, так что y = 0 можно было бы лучше подумать как y = NULL.

SmacL 29.09.2008 14:15

Я попробовал то, что вы предложили (звонок с беззнаковым длинным), но это не помогло. Александр: y изменяется с помощью A (), а z просто указывает на то же значение, что и до вызова.

Barth 29.09.2008 15:50

Хорошо, я вполне мог ошибаться, так как это было всего лишь предположением. Попробуйте проверить sizeof (unsigned long long) в обоих компиляторах. В обоих случаях должно быть 8 байтов. Если нет, то это ваша проблема и вам нужен новый прототип, иначе это что-то другое.

SmacL 29.09.2008 16:19

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

Я думаю, вам стоит редактировать свой пост, чтобы дать намного больше информации, чтобы получить некоторые разумные ответы. В частности, начнем с: -

  • Для какой платформы этот код: Windows, linux, что-то встроенное или же ...?
  • Какой компилятор C статическая библиотека, построенная с помощью?
  • Какие компилятор - это динамическая библиотека C++ построен с?
  • Какой компилятор C который может успешно вызвать библиотека построена с помощью?
  • У вас есть отладчик исходного уровня? Если да, то может вы шагаете в код C из C++.

Если вы не ошибаетесь в том, что 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 для каждого экземпляра, а также другие). Ваше здоровье !

Barth 29.09.2008 23:27

Другие вопросы по теме