Почему мой параметр, передаваемый по ссылке, не изменяется внутри функции? - PullRequest
0 голосов
/ 29 сентября 2008

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

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

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

Теперь вот что меня ошеломляет:

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

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

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

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

Ответы [ 10 ]

4 голосов
/ 29 сентября 2008

Похоже, разница между тем, как ваша библиотека C и компилятор C ++ имеют дело с long long . Я предполагаю, что библиотека C, вероятно, соответствует стандарту C89 и фактически рассматривает 64-битную long long как 32-битную long. Ваша библиотека C ++ обрабатывает ее правильно и помещает 64 бита в стек вызовов, что приводит к повреждению y и z. Возможно, попробуйте вызвать функцию через * int A (без знака int a, без знака long b, без знака int * y, без знака char z) и посмотрите, что вы получите.

Просто мысль.

2 голосов
/ 29 сентября 2008

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

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

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

Если вы не ошибаетесь в том, что A всегда изменяет данные, на которые указывает Z, единственной вероятной причиной вашей проблемы является несовместимость между соглашениями о передаче параметров. «Длинная длинная» проблема может быть намеком на то, что все не так, как кажется.

В качестве последнего средства вы можете сравнить дизассемблированный вызывающий код C ++ (который, как вы говорите, не удается) и вызывающий код C (который, как вы говорите, успешно), или пройтись по инструкциям ЦП с помощью отладчика (да, действительно - вы ') выучите хорошие навыки, а также решите проблему)

1 голос
/ 29 сентября 2008

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

Краткий ответ на мою проблему: проблема заключалась в том, что моя библиотека C ++ использовала старую версию библиотеки C. Эта старая версия пропустила 4-й аргумент. Как следствие, 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).

Не стесняйтесь редактировать этот ответ или вопрос или попросить меня сделать это.

1 голос
/ 29 сентября 2008

Опять очевидный, но кто знает ... Вы уверены, что вызываемая вами функция C не имеет состояния, то есть ее вывод зависит только от ее входных данных? Если функция не имеет состояния, то это может быть связано с тем, что «скрытое» состояние отвечает за другое поведение (не изменяя данные, на которые указывает z) функции при вызове из приложения C ++.

1 голос
/ 29 сентября 2008

Еще одна дикая догадка: вы уверены, что ссылаетесь на правильный экземпляр функции в вашей библиотеке C? Может ли быть так, что в ваших библиотеках есть несколько таких функций? В C компоновщик не заботится о типе возвращаемого значения или списке параметров при принятии решения о том, как разрешить функцию - важно только имя. Итак, если у вас есть несколько функций с одним и тем же именем ...

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

1 голос
/ 29 сентября 2008

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

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

1 голос
/ 29 сентября 2008

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

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

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

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

1 голос
/ 29 сентября 2008

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

1 голос
/ 29 сентября 2008

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

0 голосов
/ 29 сентября 2008

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

...