AP>А если эти данные в буфере? Буфер будет выровнен, а начало структуры данных может и небыть.
Просто скопируй...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Ну, например, если железо фиксирует endian, то ты, читая int как коллекцию char получаешь уже вполне определённое поведение...
Показательный пример ты можешь видеть в первом посте этого топика
Здравствуйте, Шахтер, Вы писали:
Ш>Здесь нет запрещения "простого свопинга байт/слов". Ш>Запрет на подобный аллиазинг -- вещь совершенно правильная, особенно для низкоуровнего программирования, поскольку помогает оптимизации кода. Ш>Ну и как человек, который имеет некий опыт возни с разным железом -- не встречал я ещё ни разу реальной необходимости применять грязные хаки. Ш>Обычно это делают от недостака опыта. А иногда всречается просто патологическая глупость помноженная на самоуверенность, когда человек начинает memcpy на C писать, думая, что у него получится лучше чем а CRTL.
Вот ты, как мощный Шахтер и объясни мне, как я могу написать собственный аллокатор, 100% соблюдая правило strict aliasing. Или аллокаторы пишутся тоже из за "патологической глупости помноженной на самоуверенность"?
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Шахтер, Вы писали:
Ш>>
Ш>> rol ecx, 16 ; 00000010H
Ш>>
E>А это точно быстрее обмена слов?
В большинстве современных процессоров самая дорогая операция -- обмен с памятью. Битовые же операции обычно очень дешевые (что не удивительно -- они тривиально реализуютя схемотехнически).
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, Шахтер, Вы писали:
E>>>McSeem2 прав -- такая паранойя. Если уж C/C++ позиционируются как языки для работы непосредственно с железом, то запрещение простого свопинга байт/слов выглядит полным маразмом.
Ш>>Здесь нет запрещения "простого свопинга байт/слов". Ш>>Запрет на подобный аллиазинг -- вещь совершенно правильная, особенно для низкоуровнего программирования, поскольку помогает оптимизации кода. Ш>>Ну и как человек, который имеет некий опыт возни с разным железом -- не встречал я ещё ни разу реальной необходимости применять грязные хаки. Ш>>Обычно это делают от недостака опыта. А иногда всречается просто патологическая глупость помноженная на самоуверенность, когда человек начинает memcpy на C писать, думая, что у него получится лучше чем а CRTL.
E>Ну если оставить в стороне излишнюю самоуверенность, то такие вещи, как: E>* буфера ввода-вывода, указатели на которые передаются либо как void*, либо как char*; E>* средства отладочных дампов блоков памяти, которые воспринимают void*, а затем преобразовывают его к char*.
E>они так же нелегальны?
Здравствуйте, Bell, Вы писали:
B>Здравствуйте, Шахтер, Вы писали:
B>Поправь меня, но ИМХО приведенный вариант с объединением в точности соответствует приведенному тобой первому варианту, который "will work as expected". B>
Смысл: код нелегален, но текущая версия компилятора так делать позволяет даже при включённом strict-aliasing. Потому что надо поддерживать сущестующий код.
E>>А это точно быстрее обмена слов?
Ш>В большинстве современных процессоров самая дорогая операция -- обмен с памятью. Битовые же операции обычно очень дешевые (что не удивительно -- они тривиально реализуютя схемотехнически).
С памятью — да. С кэшем -- не факт...
А с другой стороны тут на 16 двигать надо. Если это таки в цикле делается...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, McSeem2, Вы писали:
MS>Здравствуйте, Шахтер, Вы писали:
Ш>>Здесь нет запрещения "простого свопинга байт/слов". Ш>>Запрет на подобный аллиазинг -- вещь совершенно правильная, особенно для низкоуровнего программирования, поскольку помогает оптимизации кода. Ш>>Ну и как человек, который имеет некий опыт возни с разным железом -- не встречал я ещё ни разу реальной необходимости применять грязные хаки. Ш>>Обычно это делают от недостака опыта. А иногда всречается просто патологическая глупость помноженная на самоуверенность, когда человек начинает memcpy на C писать, думая, что у него получится лучше чем а CRTL.
MS>Вот ты, как мощный Шахтер и объясни мне, как я могу написать собственный аллокатор, 100% соблюдая правило strict aliasing.
Я, кажется понял, что тебя смущает. Ты просто не совсем правильно понимаешь, что именно запрещено делать. Не закапываясь в текст стандарта, просто напишу несколько примеров.
Легально.
int a=...;
unsigned *b=(unsigned *)(void *)&a;
printf("%u\n",*b);
Нелегально.
int a=...;
short *b=(short *)(void *)&a;
printf("%u\n",*b);
Манипуляции с указателями вообще под эту статью не попадают. Попадает только доступ.
Bottomline is. Если есть два объекта A *a; B *b; физическое местоположение которых пересекаются (как такое может случится -- отдельный больной вопрос), то значения этих объектов рассматриваются как "связанные" только в четко перечисленных случаях. Во всех остальных случах попытка изменить значение одного объекта меняя значение другого нелегальна. Проще говоря, результаты оптимизации будут непредсказуемые. Как в приведённом изначально примере, компилятор просто счел что вызов функции не имеет видимых побочных эффектов и выбросил его.
MS>Или аллокаторы пишутся тоже из за "патологической глупости помноженной на самоуверенность"?
Нет. Это я вообще не про тебя. Где моя большая кружка пива?
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Шахтер, Вы писали:
Ш>>>>
Ш>>>> rol ecx, 16 ; 00000010H
Ш>>>>
E>>>А это точно быстрее обмена слов?
Ш>>В большинстве современных процессоров самая дорогая операция -- обмен с памятью. Битовые же операции обычно очень дешевые (что не удивительно -- они тривиально реализуютя схемотехнически).
E>С памятью — да. С кэшем -- не факт...
Не забывай, что в первом случае у нас два чтения и две записи, а во втором по одной.
E>А с другой стороны тут на 16 двигать надо. Если это таки в цикле делается...
Короче. Исследовал я вопрос (вообще, в подобных случаях надо не гадать, а мерить). На моём нотеке (T7200 2Ghz) оба метода практически эквивалентны по скорости.
/* main.cpp */#include <stdio.h>
typedef unsigned long long uint64;
/* CPUClock() */__declspec(naked) uint64 CPUClock()
{
__asm {
rdtsc
ret
}
}
unsigned SwapHalf(unsigned val)
{
return (val<<16)|(val>>16);
}
/* test1() */void test1()
{
static volatile unsigned val=0x11112222;
val=SwapHalf(val);
}
/* test2() */void test2()
{
static volatile unsigned short val[2]={0x1111,0x2222};
unsigned short temp=val[1];
val[1]=val[0];
val[0]=temp;
}
/* Run<func>() */template <void (*func)()>
void Run(const char *name)
{
uint64 result=uint64(-1);
for(unsigned n=1000; n ;n--)
{
uint64 start=CPUClock();
for(unsigned k=1000; k ;k--) func();
uint64 stop=CPUClock();
stop-=start;
if( stop<result ) result=stop;
}
printf("%s result = %llu\n",name,result);
}
/* Run2() */void Run2()
{
uint64 result=uint64(-1);
for(unsigned n=1000; n ;n--)
{
uint64 start=CPUClock();
static volatile unsigned short val[2]={0x1111,0x2222};
__asm {
mov ecx, 1000
L:
sub ecx,1
mov dx, WORD PTR val[0]
mov ax, WORD PTR val[2]
mov WORD PTR val[2], dx
mov WORD PTR val[0], ax
jne L
}
uint64 stop=CPUClock();
stop-=start;
if( stop<result ) result=stop;
}
printf("asm swap result = %llu\n",result);
}
/* main() */int main()
{
Run<&test1>("rot16");
Run<&test1>("rot16");
Run<&test2>("swap");
Run<&test2>("swap");
Run2();
Run2();
return 0;
}
Вот результирующий ассемблер.
test2:
call ?CPUClock@@YA_KXZ ; CPUClock
mov esi, eax
mov edi, edx
; 53 :
; 54 : for(unsigned k=1000; k ;k--) func();
mov ecx, 1000 ; 000003e8H
npad 15
$LL4@Run@2:
sub ecx, 1
mov ax, WORD PTR ?val@?1??test2@@YAXXZ@4RCGC+2
mov dx, WORD PTR ?val@?1??test2@@YAXXZ@4RCGC
movzx eax, ax
mov WORD PTR ?val@?1??test2@@YAXXZ@4RCGC+2, dx
mov WORD PTR ?val@?1??test2@@YAXXZ@4RCGC, ax
jne SHORT $LL4@Run@2
; 55 :
; 56 : uint64 stop=CPUClock();
call ?CPUClock@@YA_KXZ ; CPUClock
test1:
call ?CPUClock@@YA_KXZ ; CPUClock
mov esi, eax
mov edi, edx
; 53 :
; 54 : for(unsigned k=1000; k ;k--) func();
mov ecx, 1000 ; 000003e8H
$LL4@Run:
mov eax, DWORD PTR ?val@?1??test1@@YAXXZ@4IC
rol eax, 16 ; 00000010H
sub ecx, 1
mov DWORD PTR ?val@?1??test1@@YAXXZ@4IC, eax
jne SHORT $LL4@Run
; 55 :
; 56 : uint64 stop=CPUClock();
call ?CPUClock@@YA_KXZ ; CPUClock
asm
call ?CPUClock@@YA_KXZ ; CPUClock
mov esi, eax
mov edi, edx
; 75 :
; 76 : static volatile unsigned short val[2]={0x1111,0x2222};
; 77 :
; 78 : __asm {
; 79 : mov ecx, 1000
mov ecx, 1000 ; 000003e8H
$L$1444:
; 80 : L:
; 81 : sub ecx,1
sub ecx, 1
; 82 :
; 83 : mov dx, WORD PTR val[0]
mov dx, WORD PTR ?val@?3??Run2@@YAXXZ@4RCGC
; 84 : mov ax, WORD PTR val[2]
mov ax, WORD PTR ?val@?3??Run2@@YAXXZ@4RCGC+2
; 85 : mov WORD PTR val[2], dx
mov WORD PTR ?val@?3??Run2@@YAXXZ@4RCGC+2, dx
; 86 : mov WORD PTR val[0], ax
mov WORD PTR ?val@?3??Run2@@YAXXZ@4RCGC, ax
; 87 :
; 88 : jne L
jne SHORT $L$1444
; 89 : }
; 90 :
; 91 : uint64 stop=CPUClock();
call ?CPUClock@@YA_KXZ ; CPUClock
Такты
rot16 result = 6132
rot16 result = 6132
swap result = 6264
swap result = 6276
asm swap result = 6036
asm swap result = 6048
Для продолжения нажмите любую клавишу . . .
Здравствуйте, elcste, Вы писали:
E>Здравствуйте, eao197, Вы писали:
E>>Насколько я понимаю, в C++ стандарте такого ограничения нет. Тем не менее, GCC 3.4.4 для C++ генерирует такой же проблемный код, как и для C
E>В C++ все ровно то же самое.
E>
5.17/8 If the value being stored in an object is accessed from another object that overlaps in any way the storage of the first object, then the overlap shall be exact and the two objects shall have the same type, otherwise the behavior is undefined.
Возможно, я неправильно Вас понял, но мне кажется, что цитата относится к такому:
a = b; где b overlaps a: т.е. "the first object" и "an object" это а. А в оригинальном вопросе, ИМХО, подойдет лучше 3.10/15
Of course, the code must be complete enough to compile and link.
В последних 3 строках считается, что это — big endien платформа.
Я не знаю, как там это называется с точки зрения стандарта, но
это — просто неправильно.
Здравствуйте, McSeem2, Вы писали:
... MS>Вопрос такой — что не так в этой программе? Подсказка — здесь имеется Undefined Behavior. Вопрос — Где?
... MS>Это не глюк компилятора, компилятор ведет себя совершенно корректно. Просьба к гуру — подождать пару дней с ответом, чтобы любопытные, но менее опытные попытались сами докопаться до истины. А потом я хочу задать дополнительные вопросы, возникшие в связи с этим.
Что я могу сказать, за такие стандарты и компиляторы расстреливать надо. Недостатки аппаратуры выдавать за стандарт это не просто глупость. Куда мы катимся?! И это на обычных скалярных процессорах, а что же на векторных будет. Выравнивали бы по 64байта.
И вообще тенденция не здоровая аппаратные проблемы сваливать на программистов, причем в такой извращенной форме. Это ж не вам ассемблер.
А если в конкретной реализации процессора команда умножения не будет работать для умножения на 10. Это тоже попадёт в стандарт? типа a*=10; -- нелегально, опасайтесь такого кода и пишите так: a=a+a+a+a+a+a+a+a+a+a; а еще лучше так: std::algotithms::align_safe_assign(a, std::algorithms::safe_multiply( a, reiterpret_cast<std::typeof(a).type>10UUL ));
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, McSeem2, Вы писали: А>... MS>>Вопрос такой — что не так в этой программе? Подсказка — здесь имеется Undefined Behavior. Вопрос — Где? А>... MS>>Это не глюк компилятора, компилятор ведет себя совершенно корректно. Просьба к гуру — подождать пару дней с ответом, чтобы любопытные, но менее опытные попытались сами докопаться до истины. А потом я хочу задать дополнительные вопросы, возникшие в связи с этим.
А>Что я могу сказать, за такие стандарты и компиляторы расстреливать надо. Недостатки аппаратуры выдавать за стандарт это не просто глупость. Куда мы катимся?! И это на обычных скалярных процессорах, а что же на векторных будет. Выравнивали бы по 64байта. А>И вообще тенденция не здоровая аппаратные проблемы сваливать на программистов, причем в такой извращенной форме. Это ж не вам ассемблер.
Если ты не в курсе, то С/С++ изначально был и назывался как "портабельный ассемблер".
В С++ добавлили некоторые высокоуровневые конструкции, но суть никак не меняли.
Здравствуйте, remark, Вы писали:
E>>Ну, например, если железо фиксирует endian, то ты, читая int как коллекцию char получаешь уже вполне определённое поведение...
R>Показательный пример ты можешь видеть в первом посте этого топика
К char* приводить вроде как законно...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Умный вопрос по C/C++
От:
Аноним
Дата:
04.04.08 13:24
Оценка:
Здравствуйте, remark, Вы писали:
... R>Если ты не в курсе, то С/С++ изначально был и назывался как "портабельный ассемблер". R>В С++ добавлили некоторые высокоуровневые конструкции, но суть никак не меняли.
Ага поэтому его стремятся сделать всё мене портабельным.
Да конешно пусть компилятор умеет обращаться с жуткими абстракциями, но не умеет делать примитивные операции типа борьбы с выравниванием, а взваливает всё с чем было лень бороться разработчикам компилятора на конечных пользователей этого самого компилятора, а ещё лучше включить это в стандарт, чтобы было чем оправдываться. Зачем создавать проблемы на ровном месте? Я вот не понимаю это стремление к сексу стоя в гомоке.
А>>Такой C++ нам не нужен! R>Никто никого и не заставляет...
Еще как заставляет