Информация об изменениях

Сообщение Re: Как обойти strict aliasing rule? от 17.06.2016 0:43

Изменено 17.06.2016 9:28 Erop

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

E>У меня есть некая структурка данных, и к ней надо обращаться то как к двум 32-битным беззнаковым интам, то как к одному 64-битному беззнаковому инту.


А зачем? В том смысле, что на разных платформах могут быть разные эндианы, и одно и тоже 64-битное число таким образом будет мапиться на разные пар 32-битных.
Тебе надо физически с битиками памяти работать, или таки нужны логически старшие и младшие биты?

А ещё есть второй вопрос, зачем ты хочешь, обязательно читать/писать память, а не двигать битики? Вдруг двигать битики быстрее? Например, во многих x86 процах смесь 32-битных и 64-битных инструкций дорогая...
Зачем ты хочешь мешать оптимизатору?

В общем, если ты хочешь работать с памятью напрямую, то есть речь о чём-то железячном, то пиши, читай прямо по адресам. Всё равно это никак не переносимо, а если таки речь идёт об операциях с числами, то бери сдвиги/маски и вперёд...
Только не ясно, зачем тебе маски...
struct Foo
{
    std::uint32_t value32Lo;

    std::uint32_t value32Hi;    

    std::uint64_t value64() const { return value32Lo|(((std::uint64_t)value32Hi)<<64); }   
};


E>Еще у меня была мысль про буфер char'ов: по стандарту любой тип можно алиазить массивом чаров, тогда что если записать этот в массив std::uint64_t, а прочитать два std::uint32_t — будет ли это нарушением strict aliasing rule? Очевидный ответ — да, поскольку читается один тип, а записывается другой. А может и нет. Этот момент мне неясен.



Конечно, потому, что есть разыне endians, кроме того, ещё и с выравниванием могут быть проблемы, при таком подходе...
Re: Как обойти strict aliasing rule?
Здравствуйте, Eeel, Вы писали:

E>У меня есть некая структурка данных, и к ней надо обращаться то как к двум 32-битным беззнаковым интам, то как к одному 64-битному беззнаковому инту.


А зачем? В том смысле, что на разных платформах могут быть разные эндианы, и одно и тоже 64-битное число таким образом будет мапиться на разные пар 32-битных.
Тебе надо физически с битиками памяти работать, или таки нужны логически старшие и младшие биты?

А ещё есть второй вопрос, зачем ты хочешь, обязательно читать/писать память, а не двигать битики? Вдруг двигать битики быстрее? Например, во многих x86 процах смесь 32-битных и 64-битных инструкций дорогая...
Зачем ты хочешь мешать оптимизатору?

В общем, если ты хочешь работать с памятью напрямую, то есть речь о чём-то железячном, то пиши, читай прямо по адресам. Всё равно это никак не переносимо, а если таки речь идёт об операциях с числами, то бери сдвиги/маски и вперёд...
Только не ясно, зачем тебе маски...
struct Foo
{
    std::uint32_t value32Lo;

    std::uint32_t value32Hi;    

    enum { BITS_IN_LO = 32 };
    std::uint64_t value64() const { return value32Lo|(((std::uint64_t)value32Hi)<<BITS_IN_LO); }
    void set( std::uint64_t v )
    {
        value32Lo = (std::uint32_t)v;
        value32Hi = (std::uint32_t)(v>>BITS_IN_LO);
    } 
};


E>Еще у меня была мысль про буфер char'ов: по стандарту любой тип можно алиазить массивом чаров, тогда что если записать этот в массив std::uint64_t, а прочитать два std::uint32_t — будет ли это нарушением strict aliasing rule? Очевидный ответ — да, поскольку читается один тип, а записывается другой. А может и нет. Этот момент мне неясен.



Конечно, потому, что есть разыне endians, кроме того, ещё и с выравниванием могут быть проблемы, при таком подходе...