Кросплатформенный код на C, теоретические проблемы

Рейтинг: 4Ответов: 3Опубликовано: 30.04.2015

Понимаю что вопрос дурацкий, но тем не менее :) В каких случаях неверно утверждение: "если код на pure C, использующий только стандартные библиотеки, собирается и работает под linux-32, linux-64 и win-32, то он без дополнительных мер соберётся и корректно заработает под win64"?

В принципе ответ очевиден: например, в тех случаях, где есть завязка на разрядность, совмещённая с "ифдеф виндовс". Но есть практические примеры не таких очевидных вещей?

Ответы

▲ 1Принят

Как уже было сказано выше, многое зависит не только от платформы, но и от компилятора - часто именно от компилятора.

Для разрешения ситуаций с размерами и разрядностью иногда создаются внутренние типы, фактический смысл которых зависит от платформы. Так например у Apple CGFloat в 32-битной системе это float, а в 64-битной - double.

Для пущей совместимости могу посоветовать собирать проект одним и тем же компилятором на разных платформах.

▲ 3

Ну, например вы используете тип long, который имеет разный размер на разных платформах, и приводите его к другому типу (к указателю)

      OS           arch           size
Windows       IA-32        4 bytes
Windows       Intel 64     4 bytes
Windows       IA-64        4 bytes
Linux         IA-32        4 bytes
Linux         Intel 64     8 bytes
Linux         IA-64        8 bytes
Mac OS X      IA-32        4 bytes
Mac OS X      Intel 64     8 bytes  

Visual C, Win32:

sizeof(char)=1
sizeof(wchar_t)=2
sizeof(short)=2
sizeof(int)=4
sizeof(long)=4
sizeof(long long)=8
sizeof(void*)=4
sizeof(size_t)=4

Visual C, Win64:

sizeof(char)=1
sizeof(wchar_t)=2
sizeof(short)=2
sizeof(int)=4
sizeof(long)=4
sizeof(long long)=8
sizeof(void*)=8
sizeof(size_t)=8

GCC on 32 platform:

sizeof(char)=1
sizeof(wchar_t)=4
sizeof(short)=2
sizeof(int)=4
sizeof(long)=4
sizeof(long long)=8
sizeof(void*)=4
sizeof(size_t)=4

GCC on 64 platform:

sizeof(char)=1
sizeof(wchar_t)=4
sizeof(short)=2
sizeof(int)=4
sizeof(long)=8
sizeof(long long)=8
sizeof(void*)=8
sizeof(size_t)=8
▲ 1

Довольно часто код полагается на undefined behaviour, и таким образом зависит от конкретной реализации компилятора.

Популярной ошибкой является вызов метода, не использующего локальные переменные, по NULL-указателю. Это может сработать на некоторых платформах, но по стандарту это имеет право привести к чему угодно.

То же относится к переполнению знакового целого. GNU toolchain под интеловской платформой доопределяет поведение в этом случае, но другие компиляторы — нет.


Более тонкая ошибка: чтение неинициализированной переменной есть UB по стандарту. Очень многие забывают это, считая, что она будет содержать «какое-то там значение», и ничего страшного в обращении к ней нет. Однако, на платформе IA64 (Itanium) это может привести к крешу.