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

Если у меня есть переменная c_int8_t в Фортране и я хочу интерпретировать базовые биты как целое число без знака (для индексации, а не для любой арифметики), каков наиболее эффективный способ выполнить преобразование? Я хочу сделать что-то вроде

X( some_function( my_c_int8_t_var ) ) = 1

где X — массив, а some_function должен возвращать c_int16_t, содержащий беззнаковое значение my_c_int8_t_var. Я видел варианты, включая перенос, iadd (или, я думаю, простое условное выражение с приведением и добавлением), но я хотел бы знать, что будет наиболее эффективным способом (это индексирование происходит во внутреннем цикле). Конечно, это не обязательно должна быть функция — если это можно сделать с помощью встроенного выражения, было бы здорово.

РЕДАКТИРОВАТЬ: Было бы неплохо, если бы этот подход также работал для другого целочисленного размера... то есть для получения содержимого беззнакового c_int16_t в c_int32_t и получения беззнакового c_int32_t в c_int64_t.


person robince    schedule 16.11.2012    source источник
comment
Разве нельзя объявить X, используя полный диапазон целого числа со знаком, например. integer, dimension(-huge(my_c_int8_t_var) : huge(my_c_int8_t_var)) :: X? Это было бы намного меньше хлопот.   -  person sigma    schedule 16.11.2012
comment
Я понимаю, что вы имеете в виду, но в моем случае я не использую весь диапазон - пользователь передает максимальное значение, и я соответственно выделяю массив X (X (Xm) в данный момент или X (0: (Xm-1)). Я хотел бы иметь возможность поддерживать полный диапазон беззнаковых целых чисел (поэтому можно получить до 256 без необходимости перехода к 2-байтовым данным), но никогда не выделять больше, чем необходимо для максимального предоставленного значения.   -  person robince    schedule 16.11.2012
comment
Ага, понятно; Я неправильно понял смысл вопроса.   -  person sigma    schedule 16.11.2012


Ответы (2)


Вы можете использовать функции transfer() и ichar(). Что-то вроде

X(ichar(transfer(my_c_int8_t_var,"a")))) = 1

Например

 use iso_c_binding
 write (*,*) ichar(transfer(-1_c_int8_t,"a"))

 end

возвращает 255.

Когда вы не можете найти соответствующий тип символа (например, 16-битный), я бы написал функцию, которая добавляет к значению огромный (1._my_integer_kind).

integer function indx(i)
  integer(c_int16_t),intent(in) :: i

  if (i<0) then
    indx = 2*(huge(i)+1) + i
  else
    indx = i
  end if
end function indx

or

  integer function indx2(i)
    integer(c_int8_t),intent(in) :: i

    indx2 = TRANSFER([i,0_c_int8_t],1_c_int16_t)
  end function indx2

Последний случай работает только для платформ с прямым порядком байтов.

Вы можете сделать общий интерфейс для этой функции.

 write (*,*) indx(-2_c_int16_t)

дает 65534

person Vladimir F    schedule 16.11.2012
comment
Спасибо, это как раз тот трюк, который я искал. Но это кажется специфичным для 8-битного случая. Я знаю, что это был мой пример, но я надеялся найти что-то, что также будет работать для преобразования беззнакового значения c_int16_t в c_int32_t и т. д. - person robince; 16.11.2012
comment
Спасибо - за огромный метод - разве не нужно условие? Для «положительных» значений в беззнаковых данных я не хочу ничего добавлять, добавление должно происходить только в том случае, если i‹0? (Или я запутался?) Так что тогда я беспокоился об условном замедлении, так как это внутренний цикл? - person robince; 16.11.2012
comment
Я предполагаю, что альтернативный подход состоит в том, чтобы перейти к более крупному типу, а затем выполнить побитовое И с соответствующей маской, чтобы обнулить большие биты, но я не был уверен, как это разобрать, а также не уверен, что это будет медленнее, чем добавление с условным. - person robince; 16.11.2012
comment
Но с TRANSFER очевидно, что если побитовое представление результата длиннее, чем у SOURCE, то старшие биты результата соответствуют битам SOURCE, а любые замыкающие биты заполняются произвольно. Я не уверен, какие начальные и конечные (с точки зрения больших или малых частей побитового значения)... - person robince; 16.11.2012
comment
С этими трюками вы должны знать о различиях между машинами с прямым порядком байтов и прямым порядком байтов и, как следствие, о непереносимости. - person Vladimir F; 16.11.2012
comment
ОК, но я всегда использую только x86 (-64), который имеет обратный порядок байтов? Так будет ли работать что-то вроде IAND(TRANSFER(i,1_c_int32_t), int32(huge(i))+1)? (Я не уверен, что маска будет правильной - или может ли она быть быстрее, чем маска с условным... - person robince; 16.11.2012
comment
Последнее замечание: подход эквивалентности может быть быстрее. Это зависит от оптимизации, которую может выполнить компилятор. - person Vladimir F; 16.11.2012

Что о

integer(c_int16_t) :: i, i2(2)
integer(c_int32_t) :: i32

equivalence (i32, i2)

i2(2) = 0

затем внутри цикла

i2(1) = i
X(i32) = 1

Будет ли это работать? Должен ли я поместить 16-битные данные в i2 (1) или i2 (2) для платформы с прямым порядком байтов?

person robince    schedule 16.11.2012
comment
Да, но я бы написал так, я собирался предложить вам TRANSFER([i,0_c_int8_t],1_c_int16_t) - person Vladimir F; 16.11.2012
comment
ПЕРЕДАЧА([i,(0_c_int16_t)],1_c_int32_t) - person Vladimir F; 16.11.2012
comment
О, это здорово... Я не знал, что при передаче можно смешивать массивы и скаляры! - person robince; 16.11.2012