Хотите верьте, хотите нет, этот заголовок настолько короткий, насколько я мог бы его описать, и все же опишите проблему, с которой я столкнулся!
Итак, вот сценарий: я звоню в DLL Фортрана из VBA,и DLL использует определяемые пользователем типы или любое другое имя Fortran для этого (structs?) в качестве аргумента и копирует тип обратно вызывающей стороне для проверки.
Тип имеет массив символов фиксированной длины и некоторый ряд целых чисел.
Я заметил странное поведение в любых атрибутах, определенных после этого массива символов, которые я расскажу ниже, сразу после того, как я опишу свою настройку тестирования в режиме «сворачивания»:
Сторона Фортрана:
Вот основная программа:
SUBROUTINE characterArrayTest (simpleTypeIn, simpleTypeOut)
use simpleTypeDefinition
!GCC$ ATTRIBUTES STDCALL :: characterArrayTest
type(simpleType), INTENT(IN) :: simpleTypeIn
type(simpleType), INTENT(OUT) :: simpleTypeOut
simpleTypeOut = simpleTypeIn
END SUBROUTINE characterArrayTest
А вот файл модуля simpleTypeDefinition:
Module simpleTypeDefinition
Type simpleType
character (len=1) :: CharacterArray(1)
!The length of the array is one here, but modified in tests
integer (kind=2) :: FirstInteger
integer (kind=2) :: SecondInteger
integer (kind=2) :: ThirdInteger
End Type simpleType
End Module simpleTypeDefinition
Шаг компиляции:
gfortran -c simpleTypeDefinition.f90 characterArrayTest.f90
gfortran -shared -static -o characterArrayTest.dll characterArrayTest.o
Примечание. Это 32-разрядная версия gfortran, так как я использую 32-разрядную версию Excel.
Сторона VBA:
Во-первых, зеркальные выражения типа simpleType и объявление:
Type simpleType
CharacterArray(0) As String * 1
'The length of the array is one here, but modified in tests
FirstInteger As Integer
SecondInteger As Integer
ThirdInteger As Integer
End Type
Declare Sub characterArrayTest Lib "characterArrayTest.dll" _
Alias "characterarraytest_@8" _
(simpleTypeIn As simpleType, simpleTypeOut As simpleType)
Далее, код вызова:
Dim simpleTypeIn As simpleType
Dim simpleTypeOut As simpleType
simpleTypeIn.CharacterArray(0) = "A"
'simpleTypeIn.CharacterArray(1) = "B"
'simpleTypeIn.CharacterArray(1) = "C"
'simpleTypeIn.CharacterArray(3) = "D"
simpleTypeIn.FirstInteger = 1
simpleTypeIn.SecondInteger = 2
simpleTypeIn.ThirdInteger = 3
Call Module4.characterArrayTest(simpleTypeIn, simpleTypeOut)
Странное, багги поведение:
Теперь, когда мы прошли настройку, я могу описать, что происходит:
(я играю сдлина массива символов, оставляя длину отдельных символов равной 1. Я сопоставляю параметры массива символов с обеих сторон во всех случаяхs.)
Контрольный пример: длина CharacterArray = 1
В этом первом случае все отлично работает, я передаю simpleTypeIn и simpleTypeOut из VBA,DLL-библиотека Fortran принимает ее и копирует simpleTypeIn в simpleTypeOut, а после вызова VBA возвращает simpleTypeOut с идентичными атрибутами CharacterArray, FirstInteger и т. д.
Контрольный пример: длина CharacterArray = 2
Здесь все становится интереснее.
Перед вызовом simpleTypeIn был таким, как определено.Сразу после вызова simpleTypeIn.ThirdInteger был изменен с 3 на 65!Еще более странно, что 65 является значением ASCII для символа A, которое представляет собой simpleTypeIn.CharacterArray (0).
Я проверил это соотношение, изменив «A» на «(», значение ASCII которого равно 40, и достаточно просто, simpleTypeIn.ThirdInteger изменился на 40. Странно.
В любом случаеможно было бы ожидать, что simpleTypeOut будет копией любой странной вещи, в которую SimpleTypeIn был преобразован, но не так!1069 * Контрольный пример: длина CharacterArray = 3
Этот случай был идентичен случаю 2, как ни странно.
Контрольный пример: длина CharacterArray = 4
В этом также странном случае после вызова simpleTypeIn.SecondInteger изменилось с 2 на 65, а simpleTypeIn.ThirdInteger изменилось с 3 на 66, что является значением ASCII для B.
Notчтобы быть превзойденным, simpleTypeOut.SecondInteger получился как 16961, а simpleTypeOut.ThirdInteger был 17475. Остальные значения были успешно скопированы (я разложил назначения символов B, C и D, to соответствовать размеру массива.)
Замечания:
Это странное искажение кажется линейным относительно байтов в массиве символов.Я провел некоторое тестирование, которое я внесу в каталог, если кто-то захочет в понедельник с отдельными символами длины 2 вместо 1, и повреждение произошло, когда массив имел размер 1, в отличие от ожидания, пока размер не стал равным 2. Это также нене пропускайте дополнительное искажение, когда размер массива был равен 3, как в случае с размером = 1.
Это легко для меня ошибка в зале славы;Я уверен, что вы можете себе представить, насколько это было весело, чтобы изолировать в крупномасштабной программе с кучей атрибутов Type.Если у кого-то есть какие-либо идеи, это будет с благодарностью!
Если я сразу не вернусь к вам, это потому, что я звоню один день, но я постараюсь отслеживать свой почтовый ящик.