Как корректно заполнить буфер char*
От: Аноним  
Дата: 17.03.09 09:23
Оценка:
Есть некий буфер unsigned char *buf;
нужно заполнить его int'ами или float'ами.
как это сделать корректно в рамках strict-aliasing'a,
сразу приходит в голову такое:

memcpy(buf+some_offset, &some_int_val, sizeof(int));


но может есть способ как без memcpy, но со strict-aliasing?
Re: Как корректно заполнить буфер char*
От: Tilir Россия http://tilir.livejournal.com
Дата: 17.03.09 10:32
Оценка:
Здравствуйте, Аноним, Вы писали:

А>но может есть способ как без memcpy, но со strict-aliasing?


Ну можно выкрутиться с union -- он позволит трактовать int как два байта и присвоить их по одному в нужные места. Но я бы уж лучше нарушил этот самый strict aliasing, чем занимался таким извращением.

Полезная ссылка на список большего количества трюков: http://www.cellperformance.com/mike_acton/2006/06/understanding_strict_aliasing.html
Re[2]: Как корректно заполнить буфер char*
От: Аноним  
Дата: 17.03.09 11:22
Оценка:
Здравствуйте, Tilir, Вы писали:

T>Здравствуйте, Аноним, Вы писали:


А>>но может есть способ как без memcpy, но со strict-aliasing?


T>Ну можно выкрутиться с union -- он позволит трактовать int как два байта и присвоить их по одному в нужные места. Но я бы уж лучше нарушил этот самый strict aliasing, чем занимался таким извращением.


T>Полезная ссылка на список большего количества трюков: http://www.cellperformance.com/mike_acton/2006/06/understanding_strict_aliasing.html


статью читал.
как выкрутиться с юнионом в случае с когда есть указатель на буфер чаров куда надо писать не понимаю..
Re[3]: Как корректно заполнить буфер char*
От: Erop Россия  
Дата: 17.03.09 13:46
Оценка:
Здравствуйте, Аноним, Вы писали:

А>как выкрутиться с юнионом в случае с когда есть указатель на буфер чаров куда надо писать не понимаю..

Записать int в этот юнион, а оттуда байты прочитать.

А чем тебе memcpy не нравится? Ведь тебе нужна именно её семантика?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Как корректно заполнить буфер char*
От: Аноним  
Дата: 17.03.09 14:07
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Аноним, Вы писали:


А>>как выкрутиться с юнионом в случае с когда есть указатель на буфер чаров куда надо писать не понимаю..

E>Записать int в этот юнион, а оттуда байты прочитать.

E>А чем тебе memcpy не нравится? Ведь тебе нужна именно её семантика?


думаю, что такая операция должна делаться двумя инструкциями, а не вызовом crt функции.
хотя понимаю, что не факт, что код сгенеренный с юнионом или без strictalias'a (*(int *) = 123) будет эффективней.
(предвидя следующий вопрос: да, мне важна скорость при этом
Re[5]: Как корректно заполнить буфер char*
От: Alexey F  
Дата: 17.03.09 14:23
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>думаю, что такая операция должна делаться двумя инструкциями, а не вызовом crt функции.

А>хотя понимаю, что не факт, что код сгенеренный с юнионом или без strictalias'a (*(int *) = 123) будет эффективней.
А>(предвидя следующий вопрос: да, мне важна скорость при этом

Что касается скорости: memcpy, memset и некоторые другие вполне могут быть встроены компилятором (например, при включённой оптимизации):
#include <iostream>
#include <cstdio>

int main () {
    unsigned char buffer[ 100 ];
    int a = 0xdeadface;
    std::puts ( "begin" );
    std::memcpy ( &buffer[ 0 ] + 50, &a, sizeof ( int ) );
    std::puts ( "end" );
}

Результат (-O2):
0040130B   |. C70424 00204400           MOV DWORD PTR SS:[ESP],RSDN.00442000                      ; ||ASCII "begin"
00401312   |. E8 113D0100               CALL <JMP.&msvcrt.puts>                                   ; |\puts
00401317   |. C745 BA CEFAADDE          MOV DWORD PTR SS:[EBP-46],DEADFACE                        ; |
0040131E   |. C70424 06204400           MOV DWORD PTR SS:[ESP],RSDN.00442006                      ; |ASCII "end"
00401325   |. E8 FE3C0100               CALL <JMP.&msvcrt.puts>                                   ; \puts


Или:
#include <iostream>
#include <cstdio>

int main () {
    unsigned char buffer[ 100 ];
    int a = 0xdeadface;
    std::puts ( "begin" );
    *reinterpret_cast<int*> ( &buffer[ 0 ] + 50 ) = a;
    //std::memcpy ( &buffer[ 0 ] + 50, &a, sizeof ( int ) );
    std::puts ( "end" );
}


Результат (-O2):

0040130B   |. C70424 00204400           MOV DWORD PTR SS:[ESP],RSDN.00442000                      ; ||ASCII "begin"
00401312   |. E8 113D0100               CALL <JMP.&msvcrt.puts>                                   ; |\puts
00401317   |. C745 BA CEFAADDE          MOV DWORD PTR SS:[EBP-46],DEADFACE                        ; |
0040131E   |. C70424 06204400           MOV DWORD PTR SS:[ESP],RSDN.00442006                      ; |ASCII "end"
00401325   |. E8 FE3C0100               CALL <JMP.&msvcrt.puts>                                   ; \puts


Как видите, одинаково: никаких "вызовов CRT-функций" не произошло, всё свелось к одному mov.
Re[6]: Как корректно заполнить буфер char*
От: Сергей Мухин Россия  
Дата: 21.03.09 05:58
Оценка: +1
Здравствуйте, Alexey F, Вы писали:

AF>Что касается скорости: memcpy, memset и некоторые другие вполне могут быть встроены компилятором (например, при включённой оптимизации):


да, часто компилятор вставляет инлайн для этих ф-ий. тем не менее, для x86 при больших расстояниях, memcpy, memset и тп эффективней этого самого инлайн.
---
С уважением,
Сергей Мухин
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.