Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: вопрос по memcpy
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Jenya7
функция копирует с младшего байта в младший байт. а нельзя как нибудь начиная со старшего байта в младший байт?
то есть сейчас
Код
dest[] = {0}
src[] = {1,2,3,4,5}
memcpy(dest,src,5);

и после выполнения
Код
dest = {1,2,3,4,5}

а я хочу
Код
dest = {5,4,3,2,1}



aaarrr
Стандартно - нельзя
Jenya7
Цитата(aaarrr @ Dec 2 2015, 13:17) *
Стандартно - нельзя

то есть надо переворачивать исходный массив? а есть какой нибудь быстрый алгоритм перевернуть или ничего нового не придумали?
CrimsonPig
Цитата(Jenya7 @ Dec 2 2015, 08:50) *
то есть надо переворачивать исходный массив? а есть какой нибудь быстрый алгоритм перевернуть или ничего нового не придумали?


А обязательно гонять данные по массиву туда-сюда ? Можно ли просто обращаться к его этементам в обратном порядке ?
Быстрый алгоритм можно придумать для каких-нибудь частных случаев, типа только 4 элемента по байту каждый, учесть влияние кэша процессора итп.
Jenya7
Цитата(CrimsonPig @ Dec 2 2015, 14:58) *
А обязательно гонять данные по массиву туда-сюда ? Можно ли просто обращаться к его этементам в обратном порядке ?
Быстрый алгоритм можно придумать для каких-нибудь частных случаев, типа только 4 элемента по байту каждый, учесть влияние кэша процессора итп.

тоже вариант
нет. функция посылки тоже начинает с младшего байта. лучше сразу перевернуть, быстрее будет.
Код
void ReverseArray(uint8_t *dest, uint8_t *src, uint32_t size)
{
    int i,j;
    for (i = (size - 1), j = 0; i >= 0; i--, j++)
          dest[j] = src[i];
}
CrimsonPig
Цитата(Jenya7 @ Dec 2 2015, 09:01) *
Код
void ReverseArray(uint8_t *dest, uint8_t *src, uint32_t size)
{
    int i,j;
    for (i = (size - 1), j = 0; i >= 0; i--, j++)
          dest[j] = src[i];
}


За такой код на code review коллеги сходу бьют ссаными тряпками sm.gif
- что будет, если аргумент size по какой-либо причине будет 0 ?
- аргумент src должен быть const uint8_t*
- аргумент dest желательно объявлять как void*

Jenya7
Цитата(CrimsonPig @ Dec 2 2015, 15:17) *
За такой код на code review коллеги сходу бьют ссаными тряпками sm.gif
- что будет, если аргумент size по какой-либо причине будет 0 ?

я не имею такой роскоши обложить асертами все аргументы sm.gif

Цитата(CrimsonPig @ Dec 2 2015, 15:17) *
- аргумент src должен быть const uint8_t*

ну затрут его, не жалко sm.gif

Цитата(CrimsonPig @ Dec 2 2015, 15:17) *
- аргумент dest желательно объявлять как void*

я за строгую типизацию, сэйф код sm.gif

CrimsonPig
Цитата(Jenya7 @ Dec 2 2015, 09:32) *
я не имею такой роскоши обложить асертами все аргументы sm.gif

ну затрут его, не жалко sm.gif

я за строгую типизацию, сэйф код sm.gif


Стандартные отмазки говнокодера.

код:
if(!aSize)
{
assert(0);
return;
}

не стоит практически ничего.
остальное даже комментировать не имеет смысла.

zltigo
QUOTE (CrimsonPig @ Dec 2 2015, 11:35) *
Стандартные отмазки говнокодера.

Не меньшим говнокодированием является и декларируемый Вами подход, когда куски кода для ВНУТРЕННЕГО употребления обвешиваются всякими узорами. Получается этакая борьба говнокодера с говнокодом за право говнокодировать.
CrimsonPig
Цитата(zltigo @ Dec 2 2015, 10:13) *
Не меньшим говнокодированием является и декларируемый Вами подход, когда куски кода для ВНУТРЕННЕГО употребления обвешиваются всякими узорами. Получается этакая борьба говнокодера с говнокодом за право говнокодировать.


когда в паре тысяч выпущенных в продажу девайсов такие куски кода для внутреннего употребления начнут затирать чужую память (ну, тестирование это же для ламеров) и производить занятные эффекты разной степени, вот тогда и поговорим sm.gif
zltigo
QUOTE (CrimsonPig @ Dec 2 2015, 12:26) *
когда в паре тысяч выпущенных в продажу девайсов такие куски кода для внутреннего употребления начнут затирать чужую память...

Это если их будет вызывать говнокодер. Ну и никакие assert и иже с ними не позволят вдруг сделать написанный говнокодером код рабочим. Как он НЕ работал правильно, допустим, затирая, кусок памяти, так он не будет работать ничего не делая или вылетая на assert. И не надо мне тут про тысячи, например, выпущенных в продажу кофемолок - ну не поможет никакой assert разобраться с говнокодом на кухне у конечного потребителя.
По этой причине я и написал - "борьба говнокодера с говнокодом за право говнокодировать".
CrimsonPig
Цитата(zltigo @ Dec 2 2015, 10:31) *
Это если их будет вызывать говнокодер. По этой причине я и написал - "борьба говнокодера с говнокодом за право говнокодировать".


В моем случае ассерты призваны срабатывать при проведении тестирования разных видов, вообще-то. Этим выявляется тьма абсолютно невероятных комбинаций входных воздействий, при которых говноданные таки попадают в низкоуровневые функции для "внутреннего употребления". Таких случаев выявляется ну сильно больше, чем гениальные программисты, никогда не делающие ошибок, могут себе представить.
smalcom
Код
void ReverseArray(uint8_t* pDestArr, uint8_t* pSrcArr, size_t pSize)
{
    if(pSize <= 0) return;

    pDestArr += (pSize - 1);// или "pDestArr += pSize, pDestArr--;"
    do
    {
        *pDestArr-- = *pSrcArr++;
    } while(--pSize);
}
zltigo
QUOTE (CrimsonPig @ Dec 2 2015, 12:42) *
Этим выявляется тьма абсолютно невероятных комбинаций входных воздействий..

Вот и занимайтесь ВДУМЧИВО проблемой в месте ее возникновения - при обработке входных воздействий а не в конце алгоритма. И не надо валить на "говноданные" - они имеют полное право быть ЛЮБЫМИ. Вот исходя из этого факта и следует СРАЗУ начинать строить их разборку. Тогда никаких проблем не возникает. Ежели-же начинают строить изначально паркетную разборку а потом ЛАТАТЬ и пенять на "говноданные", то тогда и появляется "необходимость" добовления всяких assert-ов в говнокод...
Сергей Борщ
Цитата(smalcom @ Dec 2 2015, 13:45) *
Да, осталось pDestArr сделать void const *, а pSrcArr сделать void *. Чтобы этой функцией можно было переворачивать любые данные, в том числе лежащие во флеше. И do { } while(--pSize) заменить на while(pSize--) {} выкинув еще одно условие и упростив исходник. После чего перейти на Си с плюсами, написав шаблон-обертку, следящую за тем, чтобы pDestArr и pSrcArr указывали на одинаковый тип.
CrimsonPig
Цитата(Сергей Борщ @ Dec 2 2015, 10:55) *
Да, осталось pDestArr сделать void const *, а pSrcArr сделать void *. Чтобы этой функцией можно было переворачивать любые данные, в том числе лежащие во флеше. И do { } while(--pSize) заменить на while(pSize--) {} выкинув еще одно условие и упростив исходник. После чего перейти на Си с плюсами, написав шаблон-обертку, следящую за тем, чтобы pDestArr и pSrcArr указывали на одинаковый тип.


Щаз вам очередной великий кодер скажет, что использовать void* некошерно, потому что правильные программисты (они не пишут ассертов, да) должны заранее знать тип передаваемого значения в функцию memcpy sm.gif
Сергей Борщ
Цитата(CrimsonPig @ Dec 2 2015, 14:12) *
должны заранее знать тип передаваемого значения в функцию memcpy sm.gif
memcopy как раз имеет аргументы void const * и void *.
Некторые знают, что это сделано специально для использования неявного приведения типов.
Jenya7

ok...надо подумать...
CrimsonPig
Цитата(Jenya7 @ Dec 2 2015, 11:35) *
спасибо. сравню в листинге sm.gif


size_t не может быть меньше нуля. Это беззнаковый тип. Нормальный компилятор должен жутко материться.
Jenya7
Цитата(Сергей Борщ @ Dec 2 2015, 17:18) *
memcopy как раз имеет аргументы void const * и void *.
Некторые знают, что это сделано специально для использования неявного приведения типов.

вылетает ошибка invalid use of void expression
Сергей Борщ
Цитата(Jenya7 @ Dec 2 2015, 14:46) *
вылетает ошибка invalid use of void expression
Где вылетает? Телепатирую: внутри функции. Я писал "что" надо сделать, а не "как". Ладно, читайте по губам:
Код
void ReverseArray(void * pDestArr, void const * pSrcArr, size_t size)
{
    uint8_t const * from = (uint8_t const *)pSrcArr;
    uint8_t * to = (uint8_t *)pDstArr + size - 1;

    while(size --)
        *to-- = *from++;
}

void test()
{
    char Result[50];
    ReverseArray(Result, "Слава мне, победителю драконов!", sizeof("Слава мне, победителю драконов!"));
}
zltigo
QUOTE (CrimsonPig @ Dec 2 2015, 13:12) *
должны заранее знать тип передаваемого значения в функцию memcpy sm.gif

Вообще-то здесь речь уже идет далеко не о библиотечной функции memcpy() которая по определению должна обладать универсальностью, ну или по крайней мере сбалансированностью между универсальностью и безошибочностью в использовании. Так что для некой внутренней функции работающей с конкретными типами данных все эти неявные приведения типов скопипащенные с memcpy() В ТОПКУ.

CrimsonPig
Цитата(Сергей Борщ @ Dec 2 2015, 11:55) *
Где вылетает? Телепатирую: внутри функции. Я писал "что" надо сделать, а не "как". Ладно, читайте по губам:
[code]void ReverseArray(void * pDestArr, void const * pSrcArr, size_t size)


Кстати, я бы смотрел на мир ширше. Тут IMHO либо надо явно указать, что функция реверсирует _байты_ в массиве (и тогда использовать явный тип указателей, void* в этом случае, наверное не имеет смысла), либо передавать void* и размер элемента массива заодно.. А то получается некая неопределенность.
E.g.
void CopyArray_ReverseBytes(uint8_t* apDest, const uint8_t* apSrc, size_t aNumBytes);
void CopyArray_Reverse(void* apDest, const void* apSrc, size_t aElemSize, size_t aNumElements);

Jenya7
Цитата(Сергей Борщ @ Dec 2 2015, 17:55) *
Где вылетает? Телепатирую: внутри функции. Я писал "что" надо сделать, а не "как". Ладно, читайте по губам:
Код
void ReverseArray(void * pDestArr, void const * pSrcArr, size_t size)
{
    uint8_t const * from = (uint8_t const *)pSrcArr;
    uint8_t * to = (uint8_t *)pDstArr + size - 1;

    while(size --)
        *to-- = *from++;
}

void test()
{
    char Result[50];
    ReverseArray(Result, "Слава мне, победителю драконов!", sizeof("Слава мне, победителю драконов!"));
}

я понял. но аргумент можно привести к нужному типу и вне функции. если понадобиться.
smalcom
Цитата
do { } while(--pSize) заменить на while(pSize--) {}

идите в отдел кадров. скажите, что вы уже некомпетентны.

Цитата
Щаз вам очередной великий кодер скажет

uint8_t - "простейшее". С ним удобна математика указателей. Можно использовать void*, но в теле тогда уже, либо использовать сумбурную запись с приведением типов, либо локально объявить нужные указатели.
Вы определитесь уже в своей толпе. Ато один размер сокращает, второй умничает... Хотите напыщенно позвенеть яйцами - вперёд в онлайн тесты по C/C++. Хоть больше "удовлетворительно" наберите.

Цитата
size_t не может быть меньше нуля

это знаковый тип, т.к. используется и для возвращения кода ошибки.
CrimsonPig
Цитата(smalcom @ Dec 2 2015, 13:07) *
это знаковый тип, т.к. используется и для возвращения кода ошибки.


Так может благородному дону пойти и погуглить "size_t ssize_t" ?
smalcom
Цитата(CrimsonPig @ Dec 2 2015, 15:39) *
Так может благородному дону пойти и погуглить "size_t ssize_t" ?

Очевидно, что есть необходимость в этом biggrin.gif
Сергей Борщ
Цитата(Jenya7 @ Dec 2 2015, 16:02) *
я понял. но аргумент можно привести к нужному типу и вне функции. если понадобится.
В почти каждой точке вызова? Вы правда считаете, что засорение исходников такими приведениями типа лучше, чем одно приведение, спрятанное в теле функции? Ваше право. Успехов в сопровождении таких исходников!

Цитата(smalcom @ Dec 2 2015, 16:07) *
идите в отдел кадров. скажите, что вы уже некомпетентны.
А теперь посмотрите на исходник, к котрому это относилось или прочитайте до конца: "выкинув еще одно условие и упростив исходник". Условие, которое было перед циклом. Если вы докажете, что результат работы изначального исходника и моего кода с while(pSize--) {} отличается - схожу.

Mahagam
а как любители ассертов ассертят то, что src и dst могут в памяти перекрываться?
для всех остальных, умеющих программировать, кроме memcpy есть и memmove.
CrimsonPig
Цитата(Mahagam @ Dec 2 2015, 15:20) *
а как любители ассертов ассертят то, что src и dst могут в памяти перекрываться?
для всех остальных, умеющих программировать, кроме memcpy есть и memmove.


Хе, я хотел написать, что я бы еще проверял, что src & dest не равны и не перекрываются, но побоялся справедливого гнева настоящих кодеров, которые ассерты не используют.
а в чем проблемы-то ? адреса известны, размер буфера тоже. Массивы по определению непрерывны.
smalcom
Исходник
Код
int main()
{
volatile int ps1 = 1;
volatile int cnt = 0;

#if 0
    while(ps1--)
    {
        cnt++;
        printf("%i, %i", cnt, ps1);
    }
    
#else
    if(ps1 > 0)
    {
        do
        {
            cnt++;
            printf("%i, %i", cnt, ps1);
        } while(--ps1);
    }
#endif

    return 0;
}


Для while{}
Код
00000000 <main>:
   0:    e3a02001     mov    r2, #1
   4:    e3a03000     mov    r3, #0
   8:    e52de004     push    {lr}       ; (str lr, [sp, #-4]!)
   c:    e24dd00c     sub    sp, sp, #12
  10:    e58d2000     str    r2, [sp]
  14:    e58d3004     str    r3, [sp, #4]



  18:    ea000006     b    38 <main+0x38>

  1c:    e59d3004     ldr    r3, [sp, #4]
  20:    e2833001     add    r3, r3, #1
  24:    e58d3004     str    r3, [sp, #4]

  28:    e59d1004     ldr    r1, [sp, #4]
  2c:    e59f0028     ldr    r0, [pc, #40]   ; 5c <main+0x5c>
  30:    e59d2000     ldr    r2, [sp]
  34:    ebfffffe     bl    0 <printf>

  38:    e59d3000     ldr    r3, [sp]
  3c:    e3530000     cmp    r3, #0
  40:    e2433001     sub    r3, r3, #1
  44:    e58d3000     str    r3, [sp]
  48:    1afffff3     bne    1c <main+0x1c>
  


  4c:    e3a00000     mov    r0, #0
  50:    e28dd00c     add    sp, sp, #12
  54:    e49de004     pop    {lr}       ; (ldr lr, [sp], #4)
  58:    e12fff1e     bx    lr
  5c:    00000000     .word    0x00000000


Для do {} while()
Код
00000000 <main>:
   0:    e3a03000     mov    r3, #0
   4:    e3a02001     mov    r2, #1
   8:    e52de004     push    {lr}       ; (str lr, [sp, #-4]!)
   c:    e24dd00c     sub    sp, sp, #12
  10:    e58d2000     str    r2, [sp]
  14:    e58d3004     str    r3, [sp, #4]



  18:    e59d3000     ldr    r3, [sp]
  1c:    e3530000     cmp    r3, #0
  20:    da00000b     ble    54 <main+0x54>

  24:    e59d3004     ldr    r3, [sp, #4]
  28:    e2833001     add    r3, r3, #1
  2c:    e58d3004     str    r3, [sp, #4]

  30:    e59d1004     ldr    r1, [sp, #4]
  34:    e59f0028     ldr    r0, [pc, #40]   ; 64 <main+0x64>
  38:    e59d2000     ldr    r2, [sp]
  3c:    ebfffffe     bl    0 <printf>
  
  40:    e59d3000     ldr    r3, [sp]
  44:    e2433001     sub    r3, r3, #1
  48:    e3530000     cmp    r3, #0
  4c:    e58d3000     str    r3, [sp]
  50:    1afffff3     bne    24 <main+0x24>



  54:    e3a00000     mov    r0, #0
  58:    e28dd00c     add    sp, sp, #12
  5c:    e49de004     pop    {lr}       ; (ldr lr, [sp], #4)
  60:    e12fff1e     bx    lr
  64:    00000000     .word    0x00000000


Компилятор gcc-5.2.0. Сборка arm-none-eabi-gcc -c 1.c -O2 -o 0.o

Что говорит букварь
Код
if() <- проверка - один раз; переход один раз в плохом случае
do
...
while <- проверка и переход каждую итерацию


Код
while <- проверка - каждую итерацию, переход - один раз в конце
{
...
} <- переход каждую итерацию

для while всегда имеем +1 переход

Цитата
но побоялся справедливого гнева настоящих кодеров, которые ассерты не используют.

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

когда запускаешь программу и видишь аварийный выход из-за какой-то ерунды во входных параметрах, хочется испепелить разработчика, который не осилил правильную передачу вверх ошибки или
использование исключения.
jcxz
Цитата(smalcom @ Dec 3 2015, 06:24) *
программа, по воможности, должна работать при любых ошибках. assert - это аварийное завершение. по сути перекладывание проблемы с разработчика на пользователя.
когда запускаешь программу и видишь аварийный выход из-за какой-то ерунды во входных параметрах, хочется испепелить разработчика, который не осилил правильную передачу вверх ошибки или
использование исключения.

Вы предлагаете не использовать assert-ы и тупо виснуть в случае неверных аргументов??? Странный подход......
Вообще-то - assert - это проверка входных условий функций. И используется как раз для отладки, для того, чтобы на стадии разработки и отладки выявить случаи передачи неверных аргументов.
Если этот assert возникает у юзера, это проблема не assert-а, а проблема в недостаточной отлаженности ПО. И даже в этом случае лучше пусть выполнится действие заложенное по assert (аварийный выход или там чего),
чем это ПО повиснет.
smalcom
Цитата
Вы предлагаете не использовать assert-ы и тупо виснуть в случае неверных аргументов???

ооо. пойду-ка я из треда.
Сергей Борщ
Цитата(smalcom @ Dec 3 2015, 03:24) *
Исходник
Код
volatile int ps1 = 1;
volatile int cnt = 0;
Это наглый мухлеж. С тем же успехом можно было отключить оптимизацию. Незачет.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.