URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID3
Нить номер: 40905
[ Назад ]

Исходное сообщение
"OpenNews: Основы написания переносимого кода"

Отправлено opennews , 26-Мрт-08 11:18 
Сергей Каличев представил перевод (http://lex.iki.rssi.ru/~serj/docs/lemmings_ru/lemmings_ru.html) статьи с описанием типичных проблем, возникающих при написании переносимого кода, некоторые из проблемы очевидны, но ошибки, с ними связанные, продолжают регулярно появляться в реальном коде.

URL: http://lex.iki.rssi.ru/~serj/docs/
Новость: http://www.opennet.me/opennews/art.shtml?num=14963


Содержание

Сообщения в этом обсуждении
"Основы написания переносимого кода"
Отправлено Аноним , 26-Мрт-08 11:18 
Куча грамматических ошибок :(

"Основы написания переносимого кода"
Отправлено Konwin , 26-Мрт-08 11:19 
Мне вот интересно - написание переносимого кода описывается уже лет 20 так - зачем писать что-то еще?

"Основы написания переносимого кода"
Отправлено Ivan_Dives , 26-Мрт-08 11:43 
revision 1.8
date: 2001/11/29 22:55:57; author: ross; state: Exp; lines: +1 -6
Delete the old BUGS section entry:
> On the VAX bytes are handled backwards from most everyone else in
> the world. This is not expected to be fixed in the near future.

не понял при чём тут вакс. Это, насколько я знаю, компьютеры, которые использовались ещё в 1970... так к чему они здесь?


"Основы написания переносимого кода"
Отправлено whirlwind , 26-Мрт-08 12:12 
это такой тончайший юмор, в конце статьи пояснение:
>В названии (``Fighting the lemmings'') нет какого-то особого смысла. Раньше мы говорили >``весь мир VAX'', а теперь весь мир -- i386 и везде работает linux. Все авторы просто >следуют за этим ``леммингом -- вожаком'' и пишут (а ещё хуже -- тестируют) код >исключительно под i386/linux.

"Основы написания переносимого кода"
Отправлено Ivan_Dives , 26-Мрт-08 12:15 
>revision 1.8
>date: 2001/11/29 22:55:57; author: ross; state: Exp; lines: +1 -6
>Delete the old BUGS section entry:
>> On the VAX bytes are handled backwards from most everyone else in
>> the world. This is not expected to be fixed in the near future.
>
>не понял при чём тут вакс. Это, насколько я знаю, компьютеры, которые
>использовались ещё в 1970... так к чему они здесь?

всё, понял


"OpenNews: Основы написания переносимого кода"
Отправлено послушайте , 26-Мрт-08 12:17 
> Хотя портирование на NetBSD/sparc64 практически является таким тестом ;-)

собственно я сейчас там на sparc64.

и вот такая конструкция:
uint8_t a[] = { 41, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 3 };

uint32_t u32 = *((uint32_t *) &a[1]);

дает Bus error.

это просто пример, пришлось определить (не дословно):
#define LOAD32(p, b)    b=(((((((uint32_t)(((b) & 0) | *(((uint8_t *)p) + 3)) << 8) | *(((uint8_t *)p) + 2)) << 8) | *(((uint8_t *)p) + 1)) << 8) | *((uint8_t *)p))

но это думаю медленно, можно как нибудь оптимизировать?


"OpenNews: Основы написания переносимого кода"
Отправлено a , 26-Мрт-08 14:15 
typedef union {
  char a[4];
  uint32_t b;
} c_t;

c_t c;

c.a[0] = 41;c.a[1] = 0;c.a[2] = 0;c.a[0] = 0;

printf("%u", c.b);


"OpenNews: Основы написания переносимого кода"
Отправлено Аноним , 26-Мрт-08 18:06 
и вот такая конструкция:
uint8_t a[] = { 41, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 3 };

uint32_t u32 = *((uint32_t *) &a[1]);

дает Bus error.


ЧУВАААК, почитай доки к gcc, в частности non-bugs.txt или как там. ЗАПРЕЩЕНО такое делать.
Чтобы это заработало у gcc есть ключик, но они говорят что в стандартах на C такое поведение не описано, поэтому сосямба. Ну и ничего что этот код совершенно непереносим из-за endianess?


"OpenNews: Основы написания переносимого кода"
Отправлено послушайте , 27-Мрт-08 10:34 

>ЧУВАААК, почитай доки к gcc, в частности non-bugs.txt или как там. ЗАПРЕЩЕНО
>такое делать.
>Чтобы это заработало у gcc есть ключик, но они говорят что в
>стандартах на C такое поведение не описано, поэтому сосямба. Ну и
>ничего что этот код совершенно непереносим из-за endianess?

ЧУВАК это просто ПРИМЕР чтобы смысл в чем ОШИБКА показать..


"OpenNews: Основы написания переносимого кода"
Отправлено Аноним , 26-Мрт-08 20:02 
> и вот такая конструкция:
> uint8_t a[] = { 41, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 3 };
> uint32_t u32 = *((uint32_t *) &a[1]);
> дает Bus error.

И это ты типа удивлен? `Вон из профессии!' (C)


"OpenNews: Основы написания переносимого кода"
Отправлено очень жаль , 27-Мрт-08 10:30 
ну чи то разорались? умные все что ли?
пытаюсь перенести игрушку одну с DOS с РЕСУРСАМИ это вам вообще о чем нибудь говорит?
а

"OpenNews: Основы написания переносимого кода"
Отправлено очень жаль , 27-Мрт-08 10:31 
для тех кто все еще ТРАМВАЕ - РЕСУРСЫ БИНАРНЫЕ

"Основы написания переносимого кода"
Отправлено pavlinux , 26-Мрт-08 23:26 
Сергей Каличев - статья полезная, перевод нужный...

Давеча, пролетало, https://www.securecoding.cert.org/confluence/display/seccode...

Уже можете переводить :)


"Основы написания переносимого кода"
Отправлено vle , 27-Мрт-08 11:10 
Мда, "К сожалению, NetBSD заботится о двоичной совместимости".
Как раз к счастью NetBSD заботиться о бинарной совместимости, и очень жаль тех, кто о ней не заботится.

"Основы написания переносимого кода"
Отправлено Аноним , 28-Мрт-08 12:56 
  Статья на слабую тройку. Перечислено только около 10% типичных ошибок программистов. Автор похоже коммитит код в NetBSD и наивно считает ее самой портабельной, да и еще незаслуженно обижает разработчиков под Linux, которая BTW поддерживает в стабильной ветке на 6 CPU архитектур больше чем NETBSD и как минимум в два раза больше платформ и MMU BSP.
----------------------------------------------------
Недопонимание переводчика:

О приведении типов указателей
В главе о приведении типов указателей попалась одна непонятная фраза: You are allowed to cast to the ``right'' type of an object when assigning via a pointer, so the compiler assumes all variables of the casted-to type might have changed. Вот комментарии автора по этому поводу:

<<Скажем, у вас есть поток байтов, который включает в себя некоторый участок, и вы хотите обратиться к этому участку, как к структуре. Поток байтов не имеет выравнивания. Для указателя на байт используется char* или void*. Теперь, если привести тип указателя к типу struct* (указатель на вашу структуру), компилятор будет считать указатель допустимым, включая все требования по выравниванию, относящиеся к указателям на вашу структуру.

Это также справедливо в случае, если вы сперва выполнили приведение типа указателя, а потом использовали memcpy() для копирования содержимого структуры.

Однако, если вы выполните memcpy(), т.е. скопируете данные по указателю с неприведённым типом void*/char* в локальную типизированную структуру, то компилятор не станет делать никаких предположений и всё будет работать нормально.>>

Этот комментарий не до конца прояснил смысл фразы. Более понятно стало после комментария от gena2x. Речь идёт об особенностях оптимизации. Был приведён следующий пример:

$ cat > test.c
#include <stdio.h>

void f(int *i, long *l) {
    printf("1.v=%ld\n", *l);
    *i = 11;
    printf("2.v=%ld\n", *l);
}

int main() {
    long b = 10;
    f((int*)&b, &b);
    printf("3.v=%ld\n", b);
}

$ gcc -O2 test.c -o test
$ ./test
1.v=10
2.v=10
3.v=11

Неожиданное значение ``2. v=10''. Обратите внимание, при компиляции использовалась оптимизация -O2. Если оптимизацию не использовать, то вывод будет другим:

$ gcc test.c -o test
$ ./test
1.v=10
2.v=11
3.v=11

При использовании оптимизации компилятор ``не заметил'', что значение *l изменилось. Если же строку ``*i = 11;'' заменить на ``*(long *)i = 11;'', то компилятор сделает предположение, что могли измениться все значения по указателям, имеющим тип long * (тип к которому приводили), и соответственно при использовании *l будет получено уже новое значение (``2.v=11'').

----------------------------------------------------------------------------
Автор перевода и gena2x жгут...
Как можно перепутать обращение к невыравненным данным (по их размеру) с проблеммой strict алиасинга в (я бы посоветовал gena2x попробовать свой тест на ветке 2.x.x - 3.x.x например )?
gcc-3.3.6 -O3 test.c
1.v=10
2.v=11
3.v=11
Результат правильный... На других 4.x.x в основном неправильный...

А если так gcc -O3 -fno-strict-aliasing test.c
то всегда то что ожидалось :)

  Да вы правильно догадались начиная с 4.x.x -O2 подразумевает -fstrict-aliasing                                                           , что дает инструкцию компилятору считать что все указатели разных типов указывают на непересекающиеся области памяти.

Таким образом рекомендуется при использовании оптимизации в GCC обязательно указывать флаг: -Wstrict-aliasing=2 тогда все проблемные места будет сразу видно:
$ gcc -O3 test.c -Wall -Wstrict-aliasing=2
test.c: In function ‘main’:
test.c:11: warning: dereferencing type-punned pointer will break strict-aliasing rules

Мои CFLAGS обычно включают седующие флаги:
-Wall -Wstrict-prototypes -Wcast-qual -Wcast-align -Wbad-function-cast -Wconversion -Wstrict-aliasing=2


"Гм..."
Отправлено gena2x , 12-Фев-09 14:34 
>Как можно перепутать обращение к невыравненным данным (по их размеру) с проблеммой strict алиасинга в (я бы посоветовал gena2x попробовать свой тест на ветке 2.x.x - 3.x.x например )?

Пример приводился для x86/linux/gcc. sizeof(int)==sizeof(long) - о каком выравнивании (по размеру) речь?

Да, надо было дописать что -fstrict-aliasing только в четвертой ветке по умолчанию включается в -O2.

>Wstrict-aliasing=2 тогда все проблемные места будет сразу видно:

Не все, к сожалению, посему придётся разобраться в проблеме.

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

Почти все, char* например - исключение.