Есть ли способ в runtime кроссплатформенно, для любого С/С++ компилятора, определить l/r endian для всех интегральных типов, включая указатель?
Пока что у меня на уме два способа, первый простой — переложить это на пользователя посредством определения соответствующего define, но это потребует открытия исходного кода библиотеки (либо её части).
Второй не менее тупой, что то вроде (код писал прямо на месте):
long l = 10;
_asm {
push l;
}
byte check;
_asm {
pop check;
}
if( check = 10 )
{
//left endian
}
else
{
//right endian
}
Что мне тоже не нравится так как это сделать с float Я пока не в курсе, разве что сравнивать с заранее подготовленным шаблоном.
p.s.
Сори если вопрос покажется глупым. Возможно я не всё ещё понимаю до конца правильно.
Во-первых, хорошо бы пользоваться общепринятыми именованиями. Оконечность — она бывает большая и малая, а не правая и левая. Во-вторых, не могу себе представить, для какой задачи это может быть нужно?
Здравствуйте, Vamp, Вы писали:
V>Во-первых, хорошо бы пользоваться общепринятыми именованиями. Оконечность — она бывает большая и малая, а не правая и левая.
Ок. Договоримся. Пусть будет так.
Во-вторых, не могу себе представить, для какой задачи это может быть нужно?
Пишу небольшую ВМ предусматриваю возможность вызова внешних (по отношению к коду ВМ) функций (пока что только для stdcall).
N>Пишу небольшую ВМ предусматриваю возможность вызова внешних (по отношению к коду ВМ) функций (пока что только для stdcall).
Непонятно. А зачем оконечность-то знать? Если преполагается, что функция может исполняться на машине с произвольной архитектурой и вызывается удаленно, то оконечность при передаче должна быть network.
Здравствуйте, Vamp, Вы писали:
N>>Пишу небольшую ВМ предусматриваю возможность вызова внешних (по отношению к коду ВМ) функций (пока что только для stdcall). V>Непонятно. А зачем оконечность-то знать? Если преполагается, что функция может исполняться на машине с произвольной архитектурой и вызывается удаленно, то оконечность при передаче должна быть network.
ВМ — это виртуальная машина. Т.е. виртуальный процессор исполняющий байткод. А оконечность нужно знать что бы правильно положить в стек аргументы при вызове "внешней функции" согласно её конвенции.
Re: Определить l/r endian в runtime
От:
Аноним
Дата:
23.12.08 17:29
Оценка:
N>Есть ли способ в runtime кроссплатформенно, для любого С/С++ компилятора, определить l/r endian для всех интегральных типов, включая указатель?
N>ВМ — это виртуальная машина. Т.е. виртуальный процессор исполняющий байткод. А оконечность нужно знать что бы правильно положить в стек аргументы при вызове "внешней функции" согласно её конвенции.
Если это виртуальный процессор, то его оконченость ты определяешь сам. Нет, чего-то я не понимаю.
Здравствуйте, nen777w, Вы писали:
N>Есть ли способ в runtime кроссплатформенно, для любого С/С++ компилятора, определить l/r endian для всех интегральных типов, включая указатель?
Понятие endian'а имеет смысл только для платформ, на которых целочисленные типы имеют побайтовое представление. Не всякая платформа такова. Например, у машины БЭСМ-6 адресовались 48-битные слова, а отдельные байты не адресовались.
С этой оговоркой, для целых можно определить endian следующим образом: взять соответствующего размера целое, скопировать в него побайтово последовательность 0x01, 0x02, ..., посмотреть, что получилось. При этом надо понимать, что для 4-байтовых целых теоретически возможны все 24 перестановки, хотя на практике как правило используются только две, известные как big и little endian.
Форматы представления плавающих чисел отличаются не только порядком байт, но и тем, например, сколько и в каком месте бит отведено на хранение мантисы и порядка, и как эти биты интерпретируются. К счастию, количество форматов, использующихся на практике, невелико, и их можно все последовательно перебрать.
Что такое endian для указателей, не вполне понятно. Но практической ценности ответ на этот вопрос не несет, т.к. указатели бессмысленно передавать между машинами: на получателе он не будет указывать ни в какое разумное место. Если хочется передать структуру какого-то хитрозалинкованного объекта, то можно ссылаться либо на идентификаторы его запчастей, либо, если на принимающей стороне возможно воспроизвести их взаимное положение в памяти, на их смещения от некоторой общей базы. В таком случае вы будете иметь дели с целыми, а про них — см. выше.
Здравствуйте, nen777w, Вы писали:
N>Есть ли способ в runtime кроссплатформенно, для любого С/С++ компилятора, определить l/r endian для всех интегральных типов, включая указатель? N>Пока что у меня на уме два способа, первый простой — переложить это на пользователя посредством определения соответствующего define, но это потребует открытия исходного кода библиотеки (либо её части).
bool is_bigendian()
{
const int t = 1;
return (*(char*)&t) == 0;
}
nen777w пишет:
> Есть ли способ в runtime кроссплатформенно, для любого С/С++ > компилятора, определить l/r endian для всех интегральных типов, включая > указатель?
В рантайме ты ничего не определишь. Там уже надо знать.
В компайл-тайме есть autoconf/configure
MZ>Vamp пишет: >> Нет, чего-то я не понимаю. MZ>+1. Чего-то он странного хочет.
Да ничего странного. Есть виртуальная машина а есть "внешние" по отношению к ВМ функции, ну например WinAPI функция из DLL — MessageBox().
У ВМ свое собственное, отличное от x386 представление чисел. В ассемблере ВМ существует команда ECALL — т.е. вызов внешней функции, описание этой функции (её адрес, конвенция, указатель, возвращаемое значение, порядок аргументов и их типов) лежат в специальной таблице.
И в какой то момент в байткоде ВМ возникает команда ECALL грубо говоря с номером в таблице где храниться описание. Так как код выполняющий инструкции ВМ это обычный x386 код, то возможность вызвать внешнюю (по отношению к байткоду ВМ) функцию нет никаких проблем, единственное что, так это надо правильно запихнуть в стек/регистры (в зависимости от конвенции вызова) аргументы для вызываемой функции.
Так как в ВМ своё представление чисел, то возникает задача, в каком порядке запихнуть байты в стек например для типа long? от малого к большому или от большого к малому.
Или Я плохо понял как нужно строить ВМ (потому что большую часть додумывал сам) или я уже не знаю как объяснить
Не надо определять endian в runtime.
Под дефайнами два разных варианта сделай. И сделай два билда.
Никому это в runtime не нужно, только тормозить будет.
8>Не надо определять endian в runtime. 8>Под дефайнами два разных варианта сделай. И сделай два билда. 8>Никому это в runtime не нужно, только тормозить будет.
Ну я собственно уже разобрался, спасибо товарищам из RSDN.
[поскипано]
N>надо правильно запихнуть в стек/регистры (в зависимости от конвенции вызова) аргументы для вызываемой функции. N>Так как в ВМ своё представление чисел, то возникает задача, в каком порядке запихнуть байты в стек например для типа long? от малого к большому или от большого к малому.
Если я Вас правильно понял, то Вы так прям и будете натурально сами руками класть значения в стек (для MessageBox, например)? Не делайте этого. Пусть компилятор сам разбирается — ему же лучше знать. Вот Вам велосипед для примера:
Тут, правда, не хватает работы со ссылками/константами и нет поддержки конвенций, отличных от дефолтной. Ещё можно сделать всяких мейкеров, чтоб инстансы basic_caller дедьюсить, можно нагородить генерацию кода с помощью Boost.Preprocessor, можно, вообще, всё это выбросить и поюзать Boost.Fusion, только не пихайте параметры в стек сами.
Если не поможет, будем действовать током... 600 Вольт (C)
ВМ может не знать интерфейса функции во время компиляции.
Во время выполнения она конечно может восстановить интерфейс по сигнатуре функции,
но тогда параметры темлейта basic_caller надо будет сформировать динамически. Как это сделать?
Вообщем придется делать велосипед который уже написан:
Для всех этих вещей есть библиотека libffi. wiki
Но даже с ней будет медленно.
Поэтому таки да, люди вручную переписывают на ассемблере и вручную кладут на стек все что надо.
Например в гуглоандройдовском дальвике так сделано.
Здравствуйте, nen777w, Вы писали:
N>Есть ли способ в runtime кроссплатформенно, для любого С/С++ компилятора, определить l/r endian для всех интегральных типов, включая указатель? N>Пока что у меня на уме два способа, первый простой — переложить это на пользователя посредством определения соответствующего define, но это потребует открытия исходного кода библиотеки (либо её части).
В runtime, как уже было сказанно, не проблема. Способы описанны выше. Только зачем определять в runtime когда в Boost уже это определенно для Compile-Time, см. BOOST_LITTLE_ENDIAN, BOOST_BIG_ENDIAN и т.п. в файле boost/detail/endian.hpp.
_>В runtime, как уже было сказанно, не проблема. Способы описанны выше. Только зачем определять в runtime когда в Boost уже это определенно для Compile-Time, см. BOOST_LITTLE_ENDIAN, BOOST_BIG_ENDIAN и т.п. в файле boost/detail/endian.hpp.
Все сводится либо к внешнему #define либо к зависимости от типа процессора
Перевести внешний #define во внутренний не трудно и без boost
А зависимость от типа процессора неоднозначная:
есть такие процессоры (например TMS320C6713), endianness которых меняется одним нажатием кнопочки.
8>Вообщем придется делать велосипед который уже написан: 8>Для всех этих вещей есть библиотека libffi. wiki
Мда.. Интересная либа. Спасибо.
То что MacOSX ppc и x86 совместимая это вообще супер.
А Вы не в курсе случайно как её собрать под win32 что бы пощупать?
Здравствуйте, nen777w, Вы писали:
N>Мда.. Интересная либа. Спасибо. N>То что MacOSX ppc и x86 совместимая это вообще супер. N>А Вы не в курсе случайно как её собрать под win32 что бы пощупать?
В макоси эта совместимость достигается тем, что каждый "универсальный" исполняемый файл и/или библиотека содержит в действительности внутри себя два совершенно независимых комплекта кода: для x86 и для ppc. При этом ppc у них big endian (хотя их процессор умеет работать в обеих режимах, но в свое время они выбрали big endian, видимо для совместимости с motorola 68000, на котором еще самые первые маки были сделаны), а x86, естественно, little endian, поскольку по-другому он не умеет.
Здравствуйте, Pzz, Вы писали:
Pzz>Здравствуйте, nen777w, Вы писали:
N>>Мда.. Интересная либа. Спасибо. N>>То что MacOSX ppc и x86 совместимая это вообще супер. N>>А Вы не в курсе случайно как её собрать под win32 что бы пощупать?
msys + mingw
Погляди еще на cinvoke, она в wiki тоже упоминается.
У неё есть проект/солюшн для студии.
Pzz>В макоси эта совместимость достигается тем, что каждый "универсальный" исполняемый файл и/или библиотека содержит в действительности внутри себя два совершенно независимых комплекта кода: для x86 и для ppc. При этом ppc у них big endian (хотя их процессор умеет работать в обеих режимах, но в свое время они выбрали big endian, видимо для совместимости с motorola 68000, на котором еще самые первые маки были сделаны), а x86, естественно, little endian, поскольку по-другому он не умеет.
nen777w имел ввиду что libffi портированна на ppc и x86 и другие процессоры.
universal binary здесь не причем
Re[2]: Определить l/r endian в runtime
От:
Аноним
Дата:
25.12.08 07:47
Оценка:
Здравствуйте, Conr, Вы писали:
C>Здравствуйте, nen777w, Вы писали:
N>>Есть ли способ в runtime кроссплатформенно, для любого С/С++ компилятора, определить l/r endian для всех интегральных типов, включая указатель? N>>Пока что у меня на уме два способа, первый простой — переложить это на пользователя посредством определения соответствующего define, но это потребует открытия исходного кода библиотеки (либо её части).
C>
C>bool is_bigendian()
C>{
C> const int t = 1;
C> return (*(char*)&t) == 0;
C>}
C>
я бы написал так, приведение указателей нарушает strict aliasing, да и код не очень отражает
что же происходит на самом деле:
union {
long val;
unsigned char bytes[sizeof(long)];
} test;
test.val = 1;
if (test.bytes[0] == 1) {
printf("little endian\n");
} else
printf("big endian\n");
Re[2]: Определить l/r endian в runtime
От:
Аноним
Дата:
25.12.08 07:59
Оценка:
Здравствуйте, MasterZiv, Вы писали:
MZ>nen777w пишет:
>> Есть ли способ в runtime кроссплатформенно, для любого С/С++ >> компилятора, определить l/r endian для всех интегральных типов, включая >> указатель?
MZ>В рантайме ты ничего не определишь. Там уже надо знать. MZ>В компайл-тайме есть autoconf/configure
Это шутка?
Если посмотреть какже autconf/configure определят little/big endian
то можно увидедть что она компилирует с программу типа
int
main ()
{
/* Are we little or big endian? From Harbison&Steele. */union
{
long int l;
char c[sizeof (long int)];
} u;
u.l = 1;
return u.c[sizeof (long int) - 1] == 1;
;
return 0;
}
а исходя из того что вернет программа (определившая результат в runtime, заметьте),
configure определяет макрос типа HOST_ENDIASS
Пощупал cinvoke — либа просто супер!
Сделал небольшой тестовый проектик под WinXP и MacOSX x86 — работает!
А вот под MacOSX для ppc-таргета проблемы, gcc не понял asm инструкции для этого процессора!? хотя universal binnary из C/C++ кода собирать умеет. Во общему думаю надо будет взять и доработать напильником.
8>ВМ может не знать интерфейса функции во время компиляции.
Что Вы имеете в виду? Зачем ей (мочь) знать интерфейс? В каких случаях она может не знать?
8>Во время выполнения она конечно может восстановить интерфейс по сигнатуре функции,
"интерфейс по сигнатуре"? В каком виде интерфейс и сигнатура?
8>но тогда параметры темлейта basic_caller надо будет сформировать динамически. Как это сделать?
Не параметры, а параметр. Это тип функции. Параметр темлейта basic_caller надо будет сформировать динамически _только_ тогда, когда у Вас появится динамически новый тип функции. Как Вы себе это представляете? Генерирование функций на лету?
М.б. Вы имеете в виду реализацию встроенной функции, наподобие writeln в паскале? Тогда можно добавить полную специализацию:
8>Вообщем придется делать велосипед который уже написан: 8>Для всех этих вещей есть библиотека libffi. wiki 8>Но даже с ней будет медленно. 8>Поэтому таки да, люди вручную переписывают на ассемблере и вручную кладут на стек все что надо.
Можно вручную положить параметры на стек быстрее, чем это делает компилятор?
8>Например в гуглоандройдовском дальвике так сделано.
Если не поможет, будем действовать током... 600 Вольт (C)
Если вы делаете скрипт\язык который имееть возможность расширяться native методами без перекомпиляции
самой VM (native методы например в dll), то ваш подход не подходит. Как вариант конечно можно заставить
каждый модуль сначала делать инициализацию своих методов.
MX>Можно вручную положить параметры на стек быстрее, чем это делает компилятор?
Да. Но я понимаю на что вы намекаете Не надо думать о "положить на стек" в буквальном смысле.
Вот ваш вариант будет медленно работать.
Здравствуйте, nen777w, Вы писали: N>Пишу небольшую ВМ предусматриваю возможность вызова внешних (по отношению к коду ВМ) функций (пока что только для stdcall).
Почему бы не хранить в байткоде VM все данные в network byte order и преобразовывать с помощью ntoh/hton в нативный порядок?
Здравствуйте, Mr.Cat, Вы писали:
N>>Пишу небольшую ВМ предусматриваю возможность вызова внешних (по отношению к коду ВМ) функций (пока что только для stdcall).
MC>Почему бы не хранить в байткоде VM все данные в network byte order и преобразовывать с помощью ntoh/hton в нативный порядок?
Это приведет к очень заметной потере эффективности, потому что такое преобразование придется делать перед и после каждой арифметической операции
Здравствуйте, Pzz, Вы писали: Pzz>Это приведет к очень заметной потере эффективности, потому что такое преобразование придется делать перед и после каждой арифметической операции
Network order можно использовать только для хранения констант в самом байткоде. А в рантайме в памяти все хранить в нативном порядке.
Либо я не понимаю, в чем проблема у автора топика.