Разница в чтении файла в i386 и amd64
От: NordWest Россия  
Дата: 07.07.11 07:15
Оценка:
Здравствуйте.
Есть одна программа, в которой выполняется чтение tiff файла. Код такой:

{
printf("Reading TIFF header...\n");
struct 
   {
   unsigned short tag,type;
   unsigned long n,val;
   } tag;
unsigned short magic,n_tags;
unsigned long ifd;
char c,flag1=0;

fread(&c,1,1,F);
if (c!='I') die ("Unsupported format!");
   
fread(&c,1,1,F);
if (c!='I') die ("Unsupported format!");
   
fread(&magic,1,2,F);
if (magic != 42) die ("Unsupported format!");
   
fread(&ifd,1,4,F);
fseek(F, ifd, SEEK_SET);
fread(&n_tags,1,2,F);

FOR(i,0,n_tags)
   {
   fread(&tag,1,12,F);
   if (tag.tag == 256) xm = tag.val;
   if (tag.tag == 257) ym = tag.val;
   if (tag.tag == 273) start = tag.val;
   if (tag.tag == 273 && tag.n > 1) flag1 = 1;   
   }
if (flag1)   
   {
   printf("Number of strips > 1 \n");
   fseek(F, start, SEEK_SET);
   fread(&start, 1, SL, F);
   }


Два компьютера с Debian 6, но разными архитектурами: i386 и amd64. Собирается одинаково:

g++ -c -o prog.obj prog.cpp
g++ -o prog.exe prog.obj -lgsl -lc -lm -lgslcblas


Но на i386 всё работает правильно, а на amd64 чтение тэгов происходит неправильно. В частности величины xm и ym оказываются равны 0. В чем тут может быть дело?
Re: Разница в чтении файла в i386 и amd64
От: Ytz https://github.com/mtrempoltsev
Дата: 07.07.11 07:28
Оценка:
Здравствуйте, NordWest, Вы писали:

NW>Но на i386 всё работает правильно, а на amd64 чтение тэгов происходит неправильно. В частности величины xm и ym оказываются равны 0. В чем тут может быть дело?


В том, что типы имеют разную длину в байтах.
Re[2]: Разница в чтении файла в i386 и amd64
От: NordWest Россия  
Дата: 07.07.11 07:36
Оценка:
Здравствуйте, Ytz, Вы писали:

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


NW>>Но на i386 всё работает правильно, а на amd64 чтение тэгов происходит неправильно. В частности величины xm и ym оказываются равны 0. В чем тут может быть дело?


Ytz>В том, что типы имеют разную длину в байтах.


Т.е. как? Значит у меня читаются 12-ти байтовые тэги tiff'а в структуру, состоящую из 2*(short)+2*(long) = 2*4 + 2*2 byte = 12 byte. Это в i386. А что будет в amd64? Типы станут вдвое длиннее?
Re[2]: Разница в чтении файла в i386 и amd64
От: NordWest Россия  
Дата: 07.07.11 08:07
Оценка:
Здравствуйте, Ytz, Вы писали:

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


NW>>Но на i386 всё работает правильно, а на amd64 чтение тэгов происходит неправильно. В частности величины xm и ym оказываются равны 0. В чем тут может быть дело?


Ytz>В том, что типы имеют разную длину в байтах.

Да, действительно, в amd64 структура в двое длиннее. А нет ли какого-нибудь простого способа собрать программу со стандартными длинами типов? Ключ может какой при компиляции указать?
Re[3]: Разница в чтении файла в i386 и amd64
От: Erop Россия  
Дата: 07.07.11 08:15
Оценка:
Здравствуйте, NordWest, Вы писали:

NW>Да, действительно, в amd64 структура в двое длиннее. А нет ли какого-нибудь простого способа собрать программу со стандартными длинами типов? Ключ может какой при компиляции указать?


1) Это вряд ли. Так как есть таки API OS...
2) Пишешь простой скрипт, который находит во всех ТВОИХ исходниках типы по списку и заменяет их на имена твоих typedefs. Пишешь под каждую архитектуру свою версию хедера с этими typedefs, и вуаля...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Разница в чтении файла в i386 и amd64
От: _nn_ www.nemerleweb.com
Дата: 07.07.11 08:21
Оценка:
Здравствуйте, NordWest, Вы писали:

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


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


NW>>>Но на i386 всё работает правильно, а на amd64 чтение тэгов происходит неправильно. В частности величины xm и ym оказываются равны 0. В чем тут может быть дело?


Ytz>>В том, что типы имеют разную длину в байтах.

NW>Да, действительно, в amd64 структура в двое длиннее. А нет ли какого-нибудь простого способа собрать программу со стандартными длинами типов? Ключ может какой при компиляции указать?

Скорее всего еще проблема с выравниванием. По умолчанию в x64 выравнивание 8, а в x86 — 4.

Можете посмотреть здесь
Автор: _nn_
Дата: 14.06.11
.

Самым лучшим способом будет использовать библиотеку для сериализации.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[4]: Разница в чтении файла в i386 и amd64
От: NordWest Россия  
Дата: 07.07.11 08:23
Оценка:
Здравствуйте, Erop, Вы писали:

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


NW>>Да, действительно, в amd64 структура в двое длиннее. А нет ли какого-нибудь простого способа собрать программу со стандартными длинами типов? Ключ может какой при компиляции указать?


E>1) Это вряд ли. Так как есть таки API OS...

E>2) Пишешь простой скрипт, который находит во всех ТВОИХ исходниках типы по списку и заменяет их на имена твоих typedefs. Пишешь под каждую архитектуру свою версию хедера с этими typedefs, и вуаля...

Не очень представляю второй пункт.

Я вот подключил inttypes.h и заменил:
unsigned short -> uint16_t
unsigned long -> uint32_t

Структура приобрела необходимый размер и этот этап программы прошел успешно. Т.е. мне теперь надо найти все такие объяления и заменить классические типы на типы из inttypes, и всё будет работать под обе архитектуры? Это только для данных типов важно или нужно все менять?

Исходники как раз не совсем мои.
Re[4]: Разница в чтении файла в i386 и amd64
От: Centaur Россия  
Дата: 07.07.11 08:25
Оценка: :)
Здравствуйте, Erop, Вы писали:

E>1) Это вряд ли. Так как есть таки API OS...

E>2) Пишешь простой скрипт, который находит во всех ТВОИХ исходниках типы по списку и заменяет их на имена твоих typedefs. Пишешь под каждую архитектуру свою версию хедера с этими typedefs, и вуаля...

«Вуаля» продлится только до того момента, когда код внезапно портируют на big-endian архитектуру. И да, там ещё где-нибудь выравнивание поплывёт.

Только аккуратно сделанная сериализация.
Re[4]: Разница в чтении файла в i386 и amd64
От: NordWest Россия  
Дата: 07.07.11 08:35
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Скорее всего еще проблема с выравниванием. По умолчанию в x64 выравнивание 8, а в x86 — 4.


__>Можете посмотреть здесь
Автор: _nn_
Дата: 14.06.11
.


__>Самым лучшим способом будет использовать библиотеку для сериализации.


Спасибо, похоже как раз моя проблема.

Там такой пример есть:

typedef double double_t;


А если мне в начале программы указать так:

typedef unsigned short uint16_t;


И для остальных типов, то в дальнейшем можно будет использовать тот же unsigned short?
Re[5]: Разница в чтении файла в i386 и amd64
От: _nn_ www.nemerleweb.com
Дата: 07.07.11 08:41
Оценка:
Здравствуйте, NordWest, Вы писали:

NW>А если мне в начале программы указать так:


NW>
NW>typedef unsigned short uint16_t;
NW>


NW>И для остальных типов, то в дальнейшем можно будет использовать тот же unsigned short?


Определение типа не такое простое.
Там ведь идут #ifdef для разных платформ.

Как раз подразумевается использование uint16_t для установления точного размера переменной.

Посмотрите как устроен stdint.h / cstdint / boost/cstdint.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[6]: Разница в чтении файла в i386 и amd64
От: NordWest Россия  
Дата: 07.07.11 08:44
Оценка:
Здравствуйте, _nn_, Вы писали:

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


NW>>А если мне в начале программы указать так:


NW>>
NW>>typedef unsigned short uint16_t;
NW>>


NW>>И для остальных типов, то в дальнейшем можно будет использовать тот же unsigned short?


__>Определение типа не такое простое.

__>Там ведь идут #ifdef для разных платформ.

__>Как раз подразумевается использование uint16_t для установления точного размера переменной.


__>Посмотрите как устроен stdint.h / cstdint / boost/cstdint.


Вот у меня как раз пошли конфликты при определении unsigned long с определениями в stdint.h. Так что так просто не выйдет
Re[5]: Разница в чтении файла в i386 и amd64
От: Erop Россия  
Дата: 07.07.11 08:48
Оценка:
Здравствуйте, Centaur, Вы писали:

E>>1) Это вряд ли. Так как есть таки API OS...

E>>2) Пишешь простой скрипт, который находит во всех ТВОИХ исходниках типы по списку и заменяет их на имена твоих typedefs. Пишешь под каждую архитектуру свою версию хедера с этими typedefs, и вуаля...

C>«Вуаля» продлится только до того момента, когда код внезапно портируют на big-endian архитектуру. И да, там ещё где-нибудь выравнивание поплывёт.

C>Только аккуратно сделанная сериализация.

Коллега спросил, как ему скомпилировать так, чтобы размеры типов были как x386. Я собственно на этот вопрос и ответил.
А так, я думаю, что ему надо взять и разобраться в своей работе, хотя бы немного...
А то "перенос кода, не приходя в сознание" -- это прикольный жанр, но я в нём не спец. Потому и смелости давать советы на себя взять не могу...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[7]: Разница в чтении файла в i386 и amd64
От: _nn_ www.nemerleweb.com
Дата: 07.07.11 08:49
Оценка:
Здравствуйте, NordWest, Вы писали:

NW>Вот у меня как раз пошли конфликты при определении unsigned long с определениями в stdint.h. Так что так просто не выйдет


Какие именно конфликты ?

#include <stdint.h>

#pragma pack(push, 8)
typedef struct tag_
{
   uint16_t tag,type;
   uint32_t n;
   uint32_t val;
} tag_t;
#pragma pack(pop)

int main()
{
 tag_t tag;
}


Вот так должно работать.
Однако не будет работать в случае big-endian <=> little-endian.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: Разница в чтении файла в i386 и amd64
От: Ops Россия  
Дата: 07.07.11 08:49
Оценка: 2 (1)
Здравствуйте, NordWest, Вы писали:

NW>Но на i386 всё работает правильно, а на amd64 чтение тэгов происходит неправильно. В частности величины xm и ym оказываются равны 0. В чем тут может быть дело?


http://www.rsdn.ru/article/cpp/XXtraps64bit.xml
Автор(ы): Андрей Карпов
Дата: 25.04.2007
Рассмотрены программные ошибки, проявляющие себя при переносе Си++ — кода с 32-битных платформ на 64-битные платформы. Приведены примеры некорректного кода и способы его исправления. Перечислены методики и средства анализа кода, позволяющие диагностировать обсуждаемые ошибки.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re: Разница в чтении файла в i386 и amd64
От: achp  
Дата: 07.07.11 09:21
Оценка:
Здравствуйте, NordWest, Вы писали:

NW>
NW>   unsigned short tag,type;
NW>   unsigned long n,val;
NW>unsigned short magic,n_tags;
NW>unsigned long ifd;
NW>


stdint.h вам уже посоветовали, а я в дополнение ещё напомню, что при чтении данных из файла неплохо бы озаботиться порядком следования байтов.
Re[2]: Разница в чтении файла в i386 и amd64
От: NordWest Россия  
Дата: 07.07.11 10:08
Оценка:
Здравствуйте, achp, Вы писали:

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


NW>>
NW>>   unsigned short tag,type;
NW>>   unsigned long n,val;
NW>>unsigned short magic,n_tags;
NW>>unsigned long ifd;
NW>>


A>stdint.h вам уже посоветовали, а я в дополнение ещё напомню, что при чтении данных из файла неплохо бы озаботиться порядком следования байтов.


Мда... Теперь задаюсь вопросом: а стоит ли оно того? Тут либо всем переходить на 64 бита и уже при написании программ по новому воспринимать размеры типов, либо отказываться от увеличенной разрядности. Прогресс/регресс. Или уже сейчас надо привыкать вместо этих short и long использовать uint32_t всякие, вне зависимости от разрядности системы, в которой пишешь. Почему не оставили в покое размеры классических типов и не добавили для 64 бит новые... Ладно, это я разворчался.
Re[3]: Разница в чтении файла в i386 и amd64
От: gegMOPO4  
Дата: 07.07.11 10:34
Оценка:
Здравствуйте, NordWest, Вы писали:
NW>Мда... Теперь задаюсь вопросом: а стоит ли оно того? Тут либо всем переходить на 64 бита и уже при написании программ по новому воспринимать размеры типов, либо отказываться от увеличенной разрядности. Прогресс/регресс. Или уже сейчас надо привыкать вместо этих short и long использовать uint32_t всякие, вне зависимости от разрядности системы, в которой пишешь. Почему не оставили в покое размеры классических типов и не добавили для 64 бит новые... Ладно, это я разворчался.

И зачем было переходить с 16 на 32 бита? Зачем увеличивать размер int-а до 32 бит? Это ведь так неудобно, сразу куча кривых программ перестало правильно компилироваться.
Re[8]: Разница в чтении файла в i386 и amd64
От: NordWest Россия  
Дата: 07.07.11 10:34
Оценка: :)
Здравствуйте, _nn_, Вы писали:

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


NW>>Вот у меня как раз пошли конфликты при определении unsigned long с определениями в stdint.h. Так что так просто не выйдет


__>Какие именно конфликты ?


__>
__>#include <stdint.h>

__>#pragma pack(push, 8)
__>typedef struct tag_
__>{
__>   uint16_t tag,type;
__>   uint32_t n;
__>   uint32_t val;
__>} tag_t;
__>#pragma pack(pop)

__>int main()
__>{
__> tag_t tag;
__>}
__>


__>Вот так должно работать.

__>Однако не будет работать в случае big-endian <=> little-endian.

Нет, я вот так хотел:

typedef unsigned short uint16_t;
typedef unsigned long uint32_t;
typedef short int16_t;
typedef long int32_t;


Но увы. Хотя может быть порядок не тот. Мне нужно, чтобы все переменные short, например, понимались как int16_t.
Re[4]: Разница в чтении файла в i386 и amd64
От: NordWest Россия  
Дата: 07.07.11 10:54
Оценка:
Здравствуйте, gegMOPO4, Вы писали:

MOP>И зачем было переходить с 16 на 32 бита? Зачем увеличивать размер int-а до 32 бит? Это ведь так неудобно, сразу куча кривых программ перестало правильно компилироваться.


Т.е. переход на другую разрядность плох только для "кривых" программ? А в правильной, по-вашему, программе нужно явно указывать разрядность переменной, если это важно для того же считывания, а не полагаться на то значение байтов, которое должно в ней содержаться по определению?

Так то, если у меня где-то вещественная переменная типа double назначена, то от разрядности системы число в ней не изменится. Диапазон только. Число значащих цифр тоже видимо.
Re[5]: Разница в чтении файла в i386 и amd64
От: achp  
Дата: 07.07.11 11:09
Оценка: 2 (1)
Здравствуйте, NordWest, Вы писали:

NW>Т.е. переход на другую разрядность плох только для "кривых" программ? А в правильной, по-вашему, программе нужно явно указывать разрядность переменной, если это важно для того же считывания, а не полагаться на то значение байтов, которое должно в ней содержаться по определению?


Разрядность — это и есть то самое определение. Просто надо понимать, что в мире программирования логически есть две линейки типов: одна с фиксированными размерами и с определённым порядком байтов, обеспечивающая общение с внешним миром (файлы, сетевые протоколы), и одна с заданными машинной архитектурой размерами и порядком байтов, обеспечивающая оптимальное использование вычислительных ресурсов.
Re[9]: Разница в чтении файла в i386 и amd64
От: _nn_ www.nemerleweb.com
Дата: 07.07.11 11:15
Оценка:
Здравствуйте, NordWest, Вы писали:

NW>Нет, я вот так хотел:


NW>
NW>typedef unsigned short uint16_t;
NW>typedef unsigned long uint32_t;
NW>typedef short int16_t;
NW>typedef long int32_t;
NW>


NW>Но увы. Хотя может быть порядок не тот. Мне нужно, чтобы все переменные short, например, понимались как int16_t.



Я вас не понимаю.
Вы хотите писать short а получить int16_t ?
А как тогда определен int16_t ?

Не нужно тут хаков. Пишите легкосопровождаемый код.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[5]: Разница в чтении файла в i386 и amd64
От: gegMOPO4  
Дата: 07.07.11 11:16
Оценка:
Здравствуйте, NordWest, Вы писали:
NW>Здравствуйте, gegMOPO4, Вы писали:
MOP>>И зачем было переходить с 16 на 32 бита? Зачем увеличивать размер int-а до 32 бит? Это ведь так неудобно, сразу куча кривых программ перестало правильно компилироваться.
NW>Т.е. переход на другую разрядность плох только для "кривых" программ? А в правильной, по-вашему, программе нужно явно указывать разрядность переменной, если это важно для того же считывания, а не полагаться на то значение байтов, которое должно в ней содержаться по определению?

В правильной программе для бинарного ввода/вывода нужно явно указывать размер целых (и не забывать о порядке байт, представлении отрицательных) и полагаться на это определение. А не додумывать что-то о текущих предпочтениях компилятора.
Re[10]: Разница в чтении файла в i386 и amd64
От: NordWest Россия  
Дата: 07.07.11 15:30
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Я вас не понимаю.

__>Вы хотите писать short а получить int16_t ?
__>А как тогда определен int16_t ?

__>Не нужно тут хаков. Пишите легкосопровождаемый код.


Нет, ну я то хочу объясниться с компилятором. Сказать ему, что short не то, что он там себе желает выдумать, а именно 16-битовое знаковое int16_t. Если уж он где то определен правильно, то пусть и под short'ом понимается то же самое.
Re[6]: Разница в чтении файла в i386 и amd64
От: NordWest Россия  
Дата: 07.07.11 15:32
Оценка:
Здравствуйте, achp, Вы писали:

A>Разрядность — это и есть то самое определение. Просто надо понимать, что в мире программирования логически есть две линейки типов: одна с фиксированными размерами и с определённым порядком байтов, обеспечивающая общение с внешним миром (файлы, сетевые протоколы), и одна с заданными машинной архитектурой размерами и порядком байтов, обеспечивающая оптимальное использование вычислительных ресурсов.


Вот спасибо за интересное замечание. Мне как раз таких вот фундаментальных представлений не хватает. Я практик, так сказать.
Re[11]: Разница в чтении файла в i386 и amd64
От: _nn_ www.nemerleweb.com
Дата: 07.07.11 15:43
Оценка:
Здравствуйте, NordWest, Вы писали:

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


__>>Я вас не понимаю.

__>>Вы хотите писать short а получить int16_t ?
__>>А как тогда определен int16_t ?

__>>Не нужно тут хаков. Пишите легкосопровождаемый код.


NW>Нет, ну я то хочу объясниться с компилятором. Сказать ему, что short не то, что он там себе желает выдумать, а именно 16-битовое знаковое int16_t. Если уж он где то определен правильно, то пусть и под short'ом понимается то же самое.


А вот так делать не стоит.
Если вам нужны конкретны типы пользуйтесь ***_t.
А общие оставьте на совести компилятора.

Вы ведь не хотите фиксированного size_t, так и другие типы пусть будут нефиксированными.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[7]: Разница в чтении файла в i386 и amd64
От: achp  
Дата: 08.07.11 10:24
Оценка:
Здравствуйте, NordWest, Вы писали:

NW>Вот спасибо за интересное замечание. Мне как раз таких вот фундаментальных представлений не хватает. Я практик, так сказать.


Это как раз тот случай, когда практика без теории слепа.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.