как портабельно узнать порядок байт в Юникоде?
От: pepsicoca  
Дата: 03.08.12 15:33
Оценка: :)
Добрый день.

Есть программа на С++, которая должна работать на разных платформах с Юникодом.

В том числе платформы различаются по параметру big-endian <-> little-endian.

Также программа должна работать с данными big-endian на платформе little-endian и с данными little-endian на платформе big-endian.

Чтобы все это осуществить, необходимо знать, на какой платформе сейчас запущена программа: на платформе big-endian или платформе little-endian.

Вопрос:

1. Как портабельно определить, на какой платформе (big-endian или little-endian) запущена программа?

Спасибо.
Re: как портабельно узнать порядок байт в Юникоде?
От: Abyx Россия  
Дата: 03.08.12 15:39
Оценка:
запишите в память, прочитайте первый байт
In Zen We Trust
Re: как портабельно узнать порядок байт в Юникоде?
От: uzhas Ниоткуда  
Дата: 03.08.12 15:45
Оценка:
Здравствуйте, pepsicoca, Вы писали:

P>1. Как портабельно определить, на какой платформе (big-endian или little-endian) запущена программа?


мне почему-то всегда казалось, что endianness фиксируется при компиляции
то бишь это все сделать через ifdef
расскажите на каких именно платформах вы планируете запускать свое приложение?
Re: как портабельно узнать порядок байт в Юникоде?
От: angry.andrew Украина  
Дата: 03.08.12 15:58
Оценка:
В общем-то достаточно узнать это при компиляции, а не проверять при выполнении, т.к. скомпилированный код всегда заточен под определенный порядок байт (по крайней мере, мне сложно представить обратное).
В бусте есть такая штука — http://www.boost.org/doc/libs/1_50_0/boost/detail/endian.hpp. Сам я не пользовался, но по идее должно работать на большинстве платформ.
Re: как портабельно узнать порядок байт в Юникоде?
От: incomoto Россия  
Дата: 03.08.12 16:13
Оценка:
Здравствуйте, pepsicoca, Вы писали:


P>Добрый день.


P>Есть программа на С++, которая должна работать на разных платформах с Юникодом.


P>В том числе платформы различаются по параметру big-endian <-> little-endian.


P>Также программа должна работать с данными big-endian на платформе little-endian и с данными little-endian на платформе big-endian.


P>Чтобы все это осуществить, необходимо знать, на какой платформе сейчас запущена программа: на платформе big-endian или платформе little-endian.


P>Вопрос:


P>1. Как портабельно определить, на какой платформе (big-endian или little-endian) запущена программа?


P>Спасибо.


http://ru.wikipedia.org/wiki/Big-endian

В частности, см. раздел "Определение порядка байтов".
What doesn't kill us, just makes us stronger.
Re: как портабельно узнать порядок байт в Юникоде?
От: AleksandrN Россия  
Дата: 07.08.12 05:31
Оценка: +1
Здравствуйте, pepsicoca, Вы писали:

P>Есть программа на С++, которая должна работать на разных платформах с Юникодом.

P>1. Как портабельно определить, на какой платформе (big-endian или little-endian) запущена программа?

P>Спасибо.


Можно использовать htons()/ntohs() или ntohl()/htonl() для преобразования порядка байт.
Re[2]: как портабельно узнать порядок байт в Юникоде?
От: chemey  
Дата: 07.08.12 06:05
Оценка:
Здравствуйте, AleksandrN, Вы писали:

P>>Есть программа на С++, которая должна работать на разных платформах с Юникодом.

P>>1. Как портабельно определить, на какой платформе (big-endian или little-endian) запущена программа?

AN>Можно использовать htons()/ntohs() или ntohl()/htonl() для преобразования порядка байт.


На big-endian платформе эти функции ничего не делают, т.к. там порядок байт уже сетевой. Могут возникнуть неприятные сюрпризы.
Гораздо проще накидать макросню для конвертации, благо макросов таких полный интернет.

И кстати да: узнать, не big-endian ли у нас платформа, можно тупо в лоб в рантайме:

if( htons(1234) == 1234 )
{
// Big-endian machine
}
else
{
// Little-endian machine
}

Хотя это уже излишество нехорошее: порядок байт известен уже при компиляции.
Бзззззззжжжжж
Re[3]: как портабельно узнать порядок байт в Юникоде?
От: pepsicoca  
Дата: 07.08.12 09:07
Оценка: :)
Здравствуйте, chemey, Вы писали:

C>Здравствуйте, AleksandrN, Вы писали:


P>>>Есть программа на С++, которая должна работать на разных платформах с Юникодом.

P>>>1. Как портабельно определить, на какой платформе (big-endian или little-endian) запущена программа?

AN>>Можно использовать htons()/ntohs() или ntohl()/htonl() для преобразования порядка байт.


C>На big-endian платформе эти функции ничего не делают, т.к. там порядок байт уже сетевой. Могут возникнуть неприятные сюрпризы.

C>Гораздо проще накидать макросню для конвертации, благо макросов таких полный интернет.

C>И кстати да: узнать, не big-endian ли у нас платформа, можно тупо в лоб в рантайме:


C>if( htons(1234) == 1234 )


Увы, это не портабельно, так как htons это функция из состава WinAPI.

C>{

C> // Big-endian machine
C>}
C>else
C>{
C> // Little-endian machine
C>}

C>Хотя это уже излишество нехорошее: порядок байт известен уже при компиляции.


Похоже, что на этапе компиляции нельзя узнать, на какой платформе (big-endian или little-endian) запущена программа.

Если в рантайме, то, действительно, можно выгрузить константу размером больше байта в память и прочитать ее побайтно, то есть попробовать что-то в этом роде:

wchar_t wch=0x100;
char* cptr=(char*)(&wch);

if(cptr[0]==0) cout<<"little-endian"; else cout<<"big-endian";
Re[4]: как портабельно узнать порядок байт в Юникоде?
От: pepsicoca  
Дата: 07.08.12 09:14
Оценка:
Здравствуйте, pepsicoca, Вы писали:

P>Здравствуйте, chemey, Вы писали:


C>>Здравствуйте, AleksandrN, Вы писали:


P>>>>Есть программа на С++, которая должна работать на разных платформах с Юникодом.

P>>>>1. Как портабельно определить, на какой платформе (big-endian или little-endian) запущена программа?

AN>>>Можно использовать htons()/ntohs() или ntohl()/htonl() для преобразования порядка байт.


C>>На big-endian платформе эти функции ничего не делают, т.к. там порядок байт уже сетевой. Могут возникнуть неприятные сюрпризы.

C>>Гораздо проще накидать макросню для конвертации, благо макросов таких полный интернет.

C>>И кстати да: узнать, не big-endian ли у нас платформа, можно тупо в лоб в рантайме:


C>>if( htons(1234) == 1234 )


P>Увы, это не портабельно, так как htons это функция из состава WinAPI.


C>>{

C>> // Big-endian machine
C>>}
C>>else
C>>{
C>> // Little-endian machine
C>>}

C>>Хотя это уже излишество нехорошее: порядок байт известен уже при компиляции.


P>Похоже, что на этапе компиляции нельзя узнать, на какой платформе (big-endian или little-endian) запущена программа.


P>Если в рантайме, то, действительно, можно выгрузить константу размером больше байта в память и прочитать ее побайтно, то есть попробовать что-то в этом роде:


P>
P>wchar_t wch=0x100;
P>char* cptr=(char*)(&wch);

P>if(cptr[0]==0) cout<<"little-endian"; else cout<<"big-endian"; 

P>


А, нет, так не прокатит на четырехбайтном юникоде.
Тогда так:


wchar_t wch=~0xff;
char* cptr=(char*)(&wch);

if(cptr[0]==0) cout<<"little-endian"; else cout<<"big-endian";
Re[4]: как портабельно узнать порядок байт в Юникоде?
От: chemey  
Дата: 07.08.12 09:45
Оценка: 1 (1)
Здравствуйте, pepsicoca, Вы писали:

P>Здравствуйте, chemey, Вы писали:


C>>И кстати да: узнать, не big-endian ли у нас платформа, можно тупо в лоб в рантайме:


C>>if( htons(1234) == 1234 )


P>Увы, это не портабельно, так как htons это функция из состава WinAPI.


Здрасьте, приехали.
Эта функция входит в состав POSIX, а следовательно, реализована на всех UNIX-платформах. В Солярисе, в Линуксе, в *BSD, в AIX и прочих HPUX она имеется (проверено электроникой).

В WinAPI, действительно, имеются свои функции, работающие с сокетами (всякие WSAAsyncSelect), но что касается htons() — она реализована в винде ровно так же, как и в юниксах. Она абсолютно автономна и ей не требуется загруженная Winsock DLL:


The htons function does not require that the Winsock DLL has previously been loaded with a successful call to the WSAStartup function.



C>>Хотя это уже излишество нехорошее: порядок байт известен уже при компиляции.


P>Похоже, что на этапе компиляции нельзя узнать, на какой платформе (big-endian или little-endian) запущена программа.


Если программа собрана для big-endian машины (например, SPARC), ты просто не сможешь ее запустить на little-endian машине (даже если это тот же SPARC в режиме little-endian). На этапе загрузки вылетит ошибка при проверке заголовка исполняемого файла (практически все современные форматы исполняемых файлов содержат поле, в котором указывается архитектура и/или endianness процессора, на котором надо программу исполнить). Даже если твой бинарь не содержит заголовка (типа com-программы под DOS), запустить ее не получится: первая же инструкция, обращающаяся к памяти по абсолютному адресу, обратится "не туда".

На практике же пропасть между big-endian и little-endian машинами такова, что ты ни при каких обстоятельствах не сможешь напрямую запустить программу, скомпилированную под big-endian платформу, на little-endian процессоре. Это возможно только под эмулятором а-ля QEMU (но при этом твоя программа, фактически, исполняется в big-endian среде).

P>
P>wchar_t wch=0x100; /* Big-Endian Solaris 64-bit: wch=0x00 00 01 00 */
P>char* cptr=(char*)(&wch); /* Big-Endian Solaris 64-bit: cptr[0] = 00 */

P>if(cptr[0]==0) cout<<"little-endian"; else cout<<"big-endian"; /* Да шо ви говогитя? */

P>


Это плохой, негодный код.
Это под виндой wchar_t гарантированно двухбайтный. Под UNIX'ами wchar_t может быть и двухбайтным, и четырехбайтным, и даже восьмибайтным ему быть никто не запрещал. Твоя проверка вернет little-endian для любой платформы, у которой wchar_t не двухбайтовый.

Если уж проверять байтики в рантайме, то проверяй последний:
int tmp = 1;
char *cptr = (char*)(&tmp);

if( cptr[0] == 1 )
    cout<<"little-endian";
else
    cout<<"big-endian";
Бзззззззжжжжж
Re[5]: как портабельно узнать порядок байт в Юникоде?
От: pepsicoca  
Дата: 07.08.12 11:46
Оценка:
Здравствуйте, chemey, Вы писали:

C>Здравствуйте, pepsicoca, Вы писали:


P>>Здравствуйте, chemey, Вы писали:


C>>>И кстати да: узнать, не big-endian ли у нас платформа, можно тупо в лоб в рантайме:


C>>>if( htons(1234) == 1234 )


P>>Увы, это не портабельно, так как htons это функция из состава WinAPI.


C>Здрасьте, приехали.

C>Эта функция входит в состав POSIX, а следовательно, реализована на всех UNIX-платформах. В Солярисе, в Линуксе, в *BSD, в AIX и прочих HPUX она имеется (проверено электроникой).

Пишем под платформы без ОС, по голому железу для микроконтроллеров.

C>В WinAPI, действительно, имеются свои функции, работающие с сокетами (всякие WSAAsyncSelect), но что касается htons() — она реализована в винде ровно так же, как и в юниксах. Она абсолютно автономна и ей не требуется загруженная Winsock DLL:



C>

C>The htons function does not require that the Winsock DLL has previously been loaded with a successful call to the WSAStartup function.



C>>>Хотя это уже излишество нехорошее: порядок байт известен уже при компиляции.


P>>Похоже, что на этапе компиляции нельзя узнать, на какой платформе (big-endian или little-endian) запущена программа.


C>Если программа собрана для big-endian машины (например, SPARC), ты просто не сможешь ее запустить на little-endian машине (даже если это тот же SPARC в режиме little-endian). На этапе загрузки вылетит ошибка при проверке заголовка исполняемого файла (практически все современные форматы исполняемых файлов содержат поле, в котором указывается архитектура и/или endianness процессора, на котором надо программу исполнить). Даже если твой бинарь не содержит заголовка (типа com-программы под DOS), запустить ее не получится: первая же инструкция, обращающаяся к памяти по абсолютному адресу, обратится "не туда".


+5
Хорошая идея — запустить бинарник от х86 на Спарке.

А если серьезно, то речь конечно же шла о переносимости кода до трансляции.


C>На практике же пропасть между big-endian и little-endian машинами такова, что ты ни при каких обстоятельствах не сможешь напрямую запустить программу, скомпилированную под big-endian платформу, на little-endian процессоре. Это возможно только под эмулятором а-ля QEMU (но при этом твоя программа, фактически, исполняется в big-endian среде).


P>>
P>>wchar_t wch=0x100; /* Big-Endian Solaris 64-bit: wch=0x00 00 01 00 */
P>>char* cptr=(char*)(&wch); /* Big-Endian Solaris 64-bit: cptr[0] = 00 */

P>>if(cptr[0]==0) cout<<"little-endian"; else cout<<"big-endian"; /* Да шо ви говогитя? */

P>>


C>Это плохой, негодный код.

C>Это под виндой wchar_t гарантированно двухбайтный. Под UNIX'ами wchar_t может быть и двухбайтным, и четырехбайтным, и даже восьмибайтным ему быть никто не запрещал. Твоя проверка вернет little-

Восьмибайтный Юникод это просто праздник для производителей памяти.
На сайте Юникод.орг написано, что юникод четырехбайтный. И в четырехбайтном-то 99% кодовой таблицы пустует.

endian для любой платформы, у которой wchar_t не двухбайтовый.

C>Если уж проверять байтики в рантайме, то проверяй последний:

C>
C>int tmp = 1;
C>char *cptr = (char*)(&tmp);

C>if( cptr[0] == 1 )
C>    cout<<"little-endian";
C>else
C>    cout<<"big-endian"; 
C>
Re[6]: как портабельно узнать порядок байт в Юникоде?
От: angry.andrew Украина  
Дата: 07.08.12 12:00
Оценка:
Если под микроконтроллеры, то это еще один аргумент в пользу определения порядка байт на этапе компиляции, т.к. наверняка при этом получится более компактный и быстрый код, чем код, умеющий и так, и так. К тому же при запуске на каждой конкретной платформе один из вариантов кода всегда будет гарантированно бездействовать.

P>Пишем под платформы без ОС, по голому железу для микроконтроллеров.
Re[7]: как портабельно узнать порядок байт в Юникоде?
От: pepsicoca  
Дата: 07.08.12 13:56
Оценка:
Здравствуйте, angry.andrew, Вы писали:

AA>Если под микроконтроллеры, то это еще один аргумент в пользу определения порядка байт на этапе компиляции, т.к. наверняка при этом получится более компактный и быстрый код, чем код, умеющий и так, и так. К тому же при запуске на каждой конкретной платформе один из вариантов кода всегда будет гарантированно бездействовать.


P>>Пишем под платформы без ОС, по голому железу для микроконтроллеров.


1. Не думаю, что буст странслируется (к примеру) иаром.
2. Не думаю, что перечисление всех известных автору на какой-то момент архитектур в макросе это хорошая идея для портабельного определения чего-либо.
3. Код не бездействует. Задача например такая: программу кормят юникодным файлом, созданным на машине с be или le системой. При этом программа сама может работать на be или le машине. Получается 4 варианта. Для корректной работы нужно при входе свопить байты юникода или не свопить байты юникода, в зависимости от. Какая система у файла можно узнать по BOM. А какая система у машины можно узнать в рантайме как тут уже предложили.
Re[8]: как портабельно узнать порядок байт в Юникоде?
От: chemey  
Дата: 07.08.12 14:17
Оценка:
Здравствуйте, pepsicoca, Вы писали:

P>Здравствуйте, angry.andrew, Вы писали:


AA>>Если под микроконтроллеры, то это еще один аргумент в пользу определения порядка байт на этапе компиляции, т.к. наверняка при этом получится более компактный и быстрый код, чем код, умеющий и так, и так. К тому же при запуске на каждой конкретной платформе один из вариантов кода всегда будет гарантированно бездействовать.


P>>>Пишем под платформы без ОС, по голому железу для микроконтроллеров.


P>1. Не думаю, что буст странслируется (к примеру) иаром.


Не обязательно тянуть весь буст в проект.
Никто ж не запрещает изучить бустовые исходники в одном конкретном месте и сделать похоже. Там достаточно свободная лицензия.

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


Тебе шашечки или ехать? Если шашечки, то можно долго строить конструкции из макросов и детекторов концеватости в рантайме, и вести философские беседы о преимуществах и недостатках разных подходов.
Если тебе ехать, на big-endian машине определяй макрос BIG_ENDIAN, на little-endian — макрос LITTLE_ENDIAN (прямо в командной строке компилятора -DBIG_ENDIAN=1). В коде используй соответствующие ифдефы. Ты ведь знаешь, надеюсь, под какую систему собираешь в данный конкретный момент?

P>3. Код не бездействует. Задача например такая: программу кормят юникодным файлом, созданным на машине с be или le системой. При этом программа сама может работать на be или le машине. Получается 4 варианта. Для корректной работы нужно при входе свопить байты юникода или не свопить байты юникода, в зависимости от. Какая система у файла можно узнать по BOM. А какая система у машины можно узнать в рантайме как тут уже предложили.


Ващета получается только два варианта: свопить (концеватость различная) или не свопить (совпадает).

В рантайме имеет смысл определять те вещи, которые могут поменяться в процессе выполнения или между запусками программы. Ты что же, собрался один и тот же бинарь попеременно запускать то на big-endian, то на little-endian архитектуре?
Бзззззззжжжжж
Re: как портабельно узнать порядок байт в Юникоде?
От: Pzz Россия https://github.com/alexpevzner
Дата: 07.08.12 14:28
Оценка: +1
Здравствуйте, pepsicoca, Вы писали:

P>Также программа должна работать с данными big-endian на платформе little-endian и с данными little-endian на платформе big-endian.


P>Чтобы все это осуществить, необходимо знать, на какой платформе сейчас запущена программа: на платформе big-endian или платформе little-endian.


А как вы собираетесь определять endian данных?

По большому счету, вам совершенно незачем знать, каков endian платформы и данных, а надо знать, совпадают они или нет.

Стандартный способ называется BOM, и при его использовании вы, собственно, и получаете ответ на этот вопрос — даже не зная endian'а платформы.
Re[9]: как портабельно узнать порядок байт в Юникоде?
От: pepsicoca  
Дата: 07.08.12 14:39
Оценка:
Здравствуйте, chemey, Вы писали:

C>Здравствуйте, pepsicoca, Вы писали:


P>>Здравствуйте, angry.andrew, Вы писали:


AA>>>Если под микроконтроллеры, то это еще один аргумент в пользу определения порядка байт на этапе компиляции, т.к. наверняка при этом получится более компактный и быстрый код, чем код, умеющий и так, и так. К тому же при запуске на каждой конкретной платформе один из вариантов кода всегда будет гарантированно бездействовать.


P>>>>Пишем под платформы без ОС, по голому железу для микроконтроллеров.


P>>1. Не думаю, что буст странслируется (к примеру) иаром.


C>Не обязательно тянуть весь буст в проект.


Буст это такая вещь, что она сама тянет за собой все, что там есть.

C>Никто ж не запрещает изучить бустовые исходники в одном конкретном месте и сделать похоже. Там достаточно свободная лицензия.


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


C>Тебе шашечки или ехать? Если шашечки, то можно долго строить конструкции из макросов и детекторов концеватости в рантайме, и вести философские беседы о преимуществах и недостатках разных подходов.

C>Если тебе ехать, на big-endian машине определяй макрос BIG_ENDIAN, на little-endian — макрос LITTLE_ENDIAN (прямо в командной строке компилятора -DBIG_ENDIAN=1). В коде используй соответствующие ифдефы. Ты ведь знаешь, надеюсь, под какую систему собираешь в данный конкретный момент?

P>>3. Код не бездействует. Задача например такая: программу кормят юникодным файлом, созданным на машине с be или le системой. При этом программа сама может работать на be или le машине. Получается 4 варианта. Для корректной работы нужно при входе свопить байты юникода или не свопить байты юникода, в зависимости от. Какая система у файла можно узнать по BOM. А какая система у машины можно узнать в рантайме как тут уже предложили.


C>Ващета получается только два варианта: свопить (концеватость различная) или не свопить (совпадает).


Два варианта исхода их четырех возможных комбинаций.

C>В рантайме имеет смысл определять те вещи, которые могут поменяться в процессе выполнения или между запусками программы. Ты что же, собрался один и тот же бинарь попеременно запускать то на big-endian, то на little-endian архитектуре?


Мечта — работать как можно меньше.
В том числе чтобы все само работало и мне не приходилось вспоминать о макросе, который определяет be или le.
Если бы такой макрос был в системе и включался автоматом, то было бы хорошо.
Если такого макроса нет, то флаг в рантайме лучше, чем свой макрос.
Один раз при старте поднял флажок и потом все процедурки на него смотрят и делают что надо.
Ну будет лишний иф, сколько там этих лишних ифоф, никто не считает.
Re[2]: как портабельно узнать порядок байт в Юникоде?
От: Mr.Delphist  
Дата: 07.08.12 15:28
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, pepsicoca, Вы писали:


P>>1. Как портабельно определить, на какой платформе (big-endian или little-endian) запущена программа?


U>мне почему-то всегда казалось, что endianness фиксируется при компиляции


Не только. Есть ещё endianness потока данных. Например, я долго не мог понять, почему некоторые TIFF-смотрелки умеют показывать ту классическую картинку с космонавтом в космосе, а некоторые — не могут. Потом покурил формат TIFF, написал свою гляделку и понял, что у картинки с космонавтом — MAC'овский endianness
Re: как портабельно узнать порядок байт в Юникоде?
От: Centaur Россия  
Дата: 07.08.12 16:08
Оценка: +2
Здравствуйте, pepsicoca, Вы писали:

P>Есть программа на С++, которая должна работать на разных платформах с Юникодом.

P>В том числе платформы различаются по параметру big-endian <-> little-endian.

Ребята, не страдайте фигнёй. Извне юникодные данные должны приходить в UTF-8. А он endian-нейтральный.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.