реклама на сайте
подробности

 
 
3 страниц V  < 1 2 3  
Reply to this topicStart new topic
> Компилятор Gcc или так и должнобыть?, Почему то отказывается выполнять инструкциии
777777
сообщение May 7 2008, 07:38
Сообщение #31


Профессионал
*****

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(Сергей Борщ @ May 7 2008, 10:48) *
Можно я чуток поправлю?
Любой указатель приводится к void* автоматически. В исходном коде компилятор не дал бы read(&var3, sizeof(var3)); только read((char *)&var3, sizeof(var3)):
Код
void read(void* pDst, uint8_t size)
{
    uint8_t *p = (uint8_t*)pDst;
    while(size--)
        *p++ = getchar();
}

Здесь создается новая переменная и pDst в нее копируется. Лучше инкрементировать саму pDst, ради этого стоит сделать ее char* и каждый раз при обращении писать преобразование типа. А если компилятор (вопреки стандарту) позволяет инкремент void* то можно оставить ее и void*
Цитата(Сергей Борщ @ May 7 2008, 10:48) *
Еще можно предположить, что размер переменной не может быть равным нулю.

А вот таких предположений лучше не делать и позволить функции не читать ни одного символа. Такое возможно если код генерируется из шаблонов, а их параметры зависят о каких-либо условий. Тогда 0, оказавшийся в размере, приведет к тому, что компилятор просто выкинет никогда не исполняющийся код.
Цитата(Сергей Борщ @ May 7 2008, 10:48) *
Ну и отсюда всего один шаг до С++:
Код
template <typename T> void read(T & Dst)
{
    uint8_t *p = (uint8_t*)&Dst;
    do
        *p++ = getchar();
    while (--size);
}

size потерялся где-то. Вероятно нужен еще sizeof(T)
Цитата(Сергей Борщ @ May 7 2008, 10:48) *
Или, если экономим код, то
Код
...
template <typename T> void read(T & Dst)
{
    read(&T, sizeof(T));
}

Если уж нас заботит экономия кода, то с шаблошами лучше не связываться... smile.gif
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение May 7 2008, 07:56
Сообщение #32


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(Сергей Борщ @ May 7 2008, 12:48) *
Можно я чуток поправлю?


Да это всё понятно:-) Я ждал какого-то мегаоткровения, а тут... :-) Так и не понял, где здесь обещанные преимущества языка высокого уровня, по сравнению, скажем, с вариантом от Редчука. Контроль типов - на программисте как был, так и остался, арифметика с указателями - как была, так и осталась. Зато столько пафоса...

Ваш, Сергей, вариант с шаблонами по крайней мере переносит часть контроля типов на компилятор.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
ReAl
сообщение May 7 2008, 09:30
Сообщение #33


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(777777 @ May 7 2008, 10:38) *
Если уж нас заботит экономия кода, то с шаблошами лучше не связываться... smile.gif
Если нас заботит экономия кода, то любой иснтрумент надо применять аккуртано. Многие монстроидальные результаты нынешнего софтостроения связаны не с примененеим С++ вообще или шаболнов в частности, а с бездумным "оттянул-уронил".
Я бы, может, и не влез, если бы не эта последняя фраза, которую я процитировал первой.

Цитата(777777 @ May 7 2008, 10:38) *
Здесь создается новая переменная и pDst в нее копируется. Лучше инкрементировать саму pDst, ради этого стоит сделать ее char* и каждый раз при обращении писать преобразование типа.
Никто ничего нового не создаёт.
К моменту использования нового указателя старый уже никому не нужен. Как следствие, его можно "выбросить", а регистры использовать по новой. Чудесным образом, в них уже есть нужное значение и ничего никуда копировать вообще не нужно (ну, за исключением копирования указателя из регистров передачи параметра в указательный регистр, у MSP430 и ARM не было бы и этого).
"Найдите десять отличий"
CODE
#include <stdint.h>
uint8_t get_byte();

void read(void* pDst, uint8_t size)
{
uint8_t *p = (uint8_t*)pDst;
while(size--)
*p++ = get_byte();
}

read:
push r17
push r28
push r29
mov r17,r22
movw r28,r24
rjmp .L2
.L3:
rcall get_byte
st Y+,r24
.L2:
subi r17,1
brcc .L3
pop r29
pop r28
pop r17
ret

CODE
#include <stdint.h>

uint8_t get_byte();

void read(uint8_t* pDst, uint8_t size)
{
while(size--)
*pDst++ = get_byte();
}

read:
push r17
push r28
push r29
movw r28,r24
mov r17,r22
rjmp .L2
.L3:
rcall get_byte
st Y+,r24
.L2:
subi r17,1
brcc .L3
pop r29
pop r28
pop r17
ret
Я нашёл только одно - в порядке копирования аргументов на новые места (впрочем, size можно было и не копировать, но это не имеет отношения к преобразованибю типов и "созданиб нового указателя").

Цитата(777777 @ May 7 2008, 10:38) *
Если уж нас заботит экономия кода, то с шаблошами лучше не связываться... smile.gif
Вернёмся. Для более правдоподобного сравнивания я в каждом варианте прочту каждый вид переменной по нескольку раз.
Чистый С, "без никаких латинских примесей"

CODE
#include <stdint.h>
uint8_t get_byte(void);

// уже выяснили, что тут uint8_t * pdst никакого выигрыша не даёт,
// а void даёт возможность применть макрос READ.
void read(void *pdst, uint8_t n)
{
uint8_t *p = (uint8_t*)pdst;
while(n--)
*p++ = get_byte();
}

#define READ(A) read( &(A), sizeof(A) )

uint8_t c0, c1, c2, c3;
uint16_t w0, w1, w2, w3;
uint32_t d0, d1, d2, d3;

void foo(void)
{
READ( c0);
READ( w0);
READ( d0);
READ( d1);
READ( w1);
READ( c1);
}

void moo(void)
{
READ( c0);
READ( c1);
READ( w0);
READ( w1);
READ( d0);
READ( d1);
}


CODE
avr-gcc -Os -mmcu=atmega88 -S
/* странно, отчёт компилятора там завысил размер этой функции, а тут занизил */
read: /* 14 */
push r17
push r28
push r29
mov r17,r22
movw r28,r24
rjmp .L2
.L3:
rcall get_byte
st Y+,r24
.L2:
subi r17,1
brcc .L3
pop r29
pop r28
pop r17
ret
/* function read size 13 (6) */

moo:
ldi r22,lo8(1)
ldi r24,lo8(c0)
ldi r25,hi8(c0)
rcall read
ldi r22,lo8(1)
ldi r24,lo8(c1)
ldi r25,hi8(c1)
rcall read
ldi r22,lo8(2)
ldi r24,lo8(w0)
ldi r25,hi8(w0)
rcall read
ldi r22,lo8(2)
ldi r24,lo8(w1)
ldi r25,hi8(w1)
rcall read
ldi r22,lo8(4)
ldi r24,lo8(d0)
ldi r25,hi8(d0)
rcall read
ldi r22,lo8(4)
ldi r24,lo8(d1)
ldi r25,hi8(d1)
rcall read
ret
/* function moo size 25 (24) */

foo:
ldi r22,lo8(1)
ldi r24,lo8(c0)
ldi r25,hi8(c0)
rcall read
ldi r22,lo8(2)
ldi r24,lo8(w0)
ldi r25,hi8(w0)
rcall read
ldi r22,lo8(4)
ldi r24,lo8(d0)
ldi r25,hi8(d0)
rcall read
ldi r22,lo8(4)
ldi r24,lo8(d1)
ldi r25,hi8(d1)
rcall read
ldi r22,lo8(2)
ldi r24,lo8(w1)
ldi r25,hi8(w1)
rcall read
ldi r22,lo8(1)
ldi r24,lo8(c1)
ldi r25,hi8(c1)
rcall read
ret
/* function foo size 25 (24) */

/* File "f1.c": code 63 = 0x003f ( 54), prologues 3, epilogues 6 */
/* 64 */


Гадкие, противные, местожрущие шаблоны.
CODE
#include <stdint.h>

uint8_t get_byte();

void read(void* pDst, uint8_t size)
{
uint8_t *p = (uint8_t*)pDst;
do
*p++ = get_byte();
while (--size);
}

template <typename T> void read(T & Dst)
{
read(&Dst, sizeof(T));
}

uint8_t c0, c1, c2, c3;
uint16_t w0, w1, w2, w3;
uint32_t d0, d1, d2, d3;

void foo(void)
{
read( c0);
read( w0);
read( d0);
read( d1);
read( w1);
read( c1);
}


void moo(void)
{
read( c0);
read( c1);
read( w0);
read( w1);
read( d0);
read( d1);
}


CODE
_Z4readPvh: /* 13 */
push r17
push r28
push r29
mov r17,r22
movw r28,r24
.L2:
rcall _Z8get_bytev
st Y+,r24
subi r17,lo8(-(-1))
brne .L2
pop r29
pop r28
pop r17
ret
/* function void read(void*, uint8_t) size 14 (7) */



_Z4readImEvRT_: /* 3 */
ldi r22,lo8(4)
rcall _Z4readPvh
ret
/* function void read(T&) [with T = uint32_t] size 3 (2) */


_Z4readIjEvRT_: /* 3 */
ldi r22,lo8(2)
rcall _Z4readPvh
ret
/* function void read(T&) [with T = uint16_t] size 3 (2) */


_Z4readIhEvRT_: /* 3 */
ldi r22,lo8(1)
rcall _Z4readPvh
ret
/* function void read(T&) [with T = uint8_t] size 3 (2) */


_Z3moov: /* 19 */
ldi r24,lo8(c0)
ldi r25,hi8(c0)
rcall _Z4readIhEvRT_
ldi r24,lo8(c1)
ldi r25,hi8(c1)
rcall _Z4readIhEvRT_
ldi r24,lo8(w0)
ldi r25,hi8(w0)
rcall _Z4readIjEvRT_
ldi r24,lo8(w1)
ldi r25,hi8(w1)
rcall _Z4readIjEvRT_
ldi r24,lo8(d0)
ldi r25,hi8(d0)
rcall _Z4readImEvRT_
ldi r24,lo8(d1)
ldi r25,hi8(d1)
rcall _Z4readImEvRT_
ret
/* function void moo() size 19 (18) */

_Z3foov: /* 19 */
ldi r24,lo8(c0)
ldi r25,hi8(c0)
rcall _Z4readIhEvRT_
ldi r24,lo8(w0)
ldi r25,hi8(w0)
rcall _Z4readIjEvRT_
ldi r24,lo8(d0)
ldi r25,hi8(d0)
rcall _Z4readImEvRT_
ldi r24,lo8(d1)
ldi r25,hi8(d1)
rcall _Z4readImEvRT_
ldi r24,lo8(w1)
ldi r25,hi8(w1)
rcall _Z4readIjEvRT_
ldi r24,lo8(c1)
ldi r25,hi8(c1)
rcall _Z4readIhEvRT_
ret
/* function void foo() size 19 (18) */

/* File "f2.cpp": code 61 = 0x003d ( 49), prologues 3, epilogues 9 */
/* 60 */

Итого вариант с шаблонами версии "если хочеться экономить код" дал выигрыш в 3 слова программной памяти (лишний rjmp в функции read C-шного варианта не считаем) . Или, на этом участке, около 5%.
Обратите внимание - "проигрыш" шаблонов в сгенерированных при специализации шаблона функциях (9 слов), а выигрыш - при каждом применении шаблонного чтения (1 слово, тут 12 применений, 3 слова выигрыша). И чем больше будет чтений, тем больше будет выигрыш.
"догнать" на С можно, заведя самостоятельно функции и производя "закат солнца вручную".
Перегнать не выйдет.
CODE
#include <stdint.h>

uint8_t get_byte(void);

void read(void *pdst, uint8_t n)
{
uint8_t *p = (uint8_t*)pdst;
while(n--)
*p++ = get_byte();
}

void read_u8(uint8_t *p) { read(p, sizeof(uint8_t) ); }
void read_u16(uint16_t *p) { read(p, sizeof(uint16_t) ); }
void read_u32(uint32_t *p) { read(p, sizeof(uint32_t) ); }

uint8_t c0, c1, c2, c3;
uint16_t w0, w1, w2, w3;
uint32_t d0, d1, d2, d3;

void foo(void)
{
read_u8( &c0);
read_u16( &w0);
read_u32( &d0);
read_u32( &d1);
read_u16( &w1);
read_u8( &c1);
}


void moo(void)
{
read_u8( &c0);
read_u8( &c1);
read_u16( &w0);
read_u16( &w1);
read_u32( &d0);
read_u32( &d1);
}


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение May 7 2008, 09:51
Сообщение #34


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(777777 @ May 7 2008, 10:38) *
А вот таких предположений лучше не делать и позволить функции не читать ни одного символа. Такое возможно если код генерируется из шаблонов, а их параметры зависят о каких-либо условий. Тогда 0, оказавшийся в размере, приведет к тому, что компилятор просто выкинет никогда не исполняющийся код.
Эту проверку можно сделать перед вызовом функции, когда принимается решение - в какую переменную читать. Ведь проверка все равно нужна, а код цикла do {} while(--size) будет короче чем while(size--) {} и в байтах кода и в тактах.
Цитата(777777 @ May 7 2008, 10:38) *
size потерялся где-то. Вероятно нужен еще sizeof(T)
Да, конечно. надо было еще добавить uint8_t size = sizeof(T);
Ну а про шаблоны ReAl все изложил с фактами наперевес. Добавлю лишь, что можно добиться на выходе точно такого же кода, как и в С-варианте, если сделать шаблонную функцию inline. А преимущество будет в том, что не ошибешься, указав имя одной переменной а sizeof другой. Пусть рутину выполняет компилятор.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
alexander55
сообщение May 7 2008, 10:02
Сообщение #35


Бывалый
*****

Группа: Свой
Сообщений: 1 584
Регистрация: 7-08-07
Пользователь №: 29 615



Цитата(Олег. @ May 2 2008, 08:17) *
unsigned long int a[] = {1, 2, 3, 4, 5};
unsigned long int b[5];

void* ptr = a;

b[0] = *((unsigned long int*)ptr)++;
b[1] = *((unsigned long long int*)ptr)++;


unsigned long int a[] = {1, 2, 3, 4, 5};
unsigned long int b[5];

unsigned long * ptr = a;

b[0] = (*ptr)++; // или же м.б. b[0] = *ptr++; или b[0] = *(ptr++); Что Вы хотите - Вам виднее.
b[1] = *ptr++;
PS. Все современные языки борются с указателями неявного типа. Это источник глюков.



Цитата(zltigo @ May 2 2008, 12:38) *
Без "кажется" - компилятор который молча инкрементирует указатель на неизвестный объект не может быть признан компилятором sad.gif

И я о том же.

Цитата(777777 @ May 2 2008, 18:58) *
А почему бы не сделать сразу этот указатель на unsigned long - и не придется ничего преобразовывать?

Наверное, для науки надо (как делать не надо). biggrin.gif
Go to the top of the page
 
+Quote Post
777777
сообщение May 7 2008, 11:46
Сообщение #36


Профессионал
*****

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(ReAl @ May 7 2008, 13:30) *
Никто ничего нового не создаёт.
К моменту использования нового указателя старый уже никому не нужен. Как следствие, его можно "выбросить", а регистры использовать по новой.

Все это конечно так, но компилятор не знает о том, что старый аргумент никому не нужен, поэтому в общем случае ему придется создавать новую еременную. Правда, в этом конкретном случае он проявил чудеса догадливости и действительно не стал ее создавать, но я не уверен что так будет если функция окажется большой и сложной.
Цитата(ReAl @ May 7 2008, 13:30) *
...
// а void даёт возможность применть макрос READ.

а при чем тут макрос? Ничего общего с шаблоном у него нет.
Цитата(ReAl @ May 7 2008, 13:30) *
Для более правдоподобного сравнивания я в каждом варианте прочту каждый вид переменной по нескольку раз.

Я извиняюсь, но это сделано не для "более правдоподобного сравнивания", а для того, чтобы вариант с шаблонами оказался короче smile.gif Достаточно оставить 5 чтений вместо 6 - и результат резко меняется. Но и с шестью чтениями, стоит добавить еще один тип данных - и он вновь окажется длинее за счет появления еще одной инстанцированной функции.
Цитата(ReAl @ May 7 2008, 13:30) *
Если нас заботит экономия кода, то любой иснтрумент надо применять аккуртано. Многие монстроидальные результаты нынешнего софтостроения связаны не с примененеим С++ вообще или шаболнов в частности, а с бездумным "оттянул-уронил".

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

Сообщение отредактировал 777777 - May 7 2008, 11:47
Go to the top of the page
 
+Quote Post
ReAl
сообщение May 7 2008, 12:59
Сообщение #37


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(777777 @ May 7 2008, 14:46) *
Все это конечно так, но компилятор не знает о том, что старый аргумент никому не нужен, поэтому в общем случае ему придется создавать новую еременную. Правда, в этом конкретном случае он проявил чудеса догадливости и действительно не стал ее создавать, но я не уверен что так будет если функция окажется большой и сложной.

Он не догадывается, он знает. Он, знаете ли, отслеживает использование каждой переменной и при необходимости использует регистры, которые занимала одна переменная, для другой.
Да, на сложных функциях очень много вариантов размещения и оптимизатор не всегда выберет идеальный, но на сложных функциях и человек не всегда всё сообразит.

Цитата(777777 @ May 7 2008, 14:46) *
а при чем тут макрос? Ничего общего с шаблоном у него нет.
А я разве сказал, что у него есть что-то общее с шаблоном? 07.gif
С ним чисто С-шный текст быстрее пишется и меньше шансов ошибиться, подсунув не тот sizeof. Вот и всё.


Цитата(777777 @ May 7 2008, 14:46) *
Я извиняюсь, но это сделано не для "более правдоподобного сравнивания", а для того, чтобы вариант с шаблонами оказался короче smile.gif Достаточно оставить 5 чтений вместо 6 - и результат резко меняется. Но и с шестью чтениями, стоит добавить еще один тип данных - и он вновь окажется длинее за счет появления еще одной инстанцированной функции.
Зависит от построения программы, конечно, но если Вам более правдоподобными кажутся программы, в которых из потока вынимается в одном единственном месте по одной единственной переменной каждого типа, то да, в Вашем случае шаблоны проиграют. В случае данной платформы - по два слова программной памяти на каждом типе. Это, безусловно, катастрофическая величина, позволяющая говорить "если важен размер, с шаблонами лучше не связываться".
Уже при трёх чтениях переменной каждого типа шаблонный вариант не проигрывает.
На вполне вероятных количествах чтений 4 и больше - выигрывает. Выигрывает не столько, чтобы плясать от радости, но я только хотел показать, что "слухи о безусловной вредности шаблонов для комплекции программы несколько преувеличены", при количествах чтений от 1 до 5 на тип - 50/50. И даже в случае проигрыша - он чепуховый.

Цитата(777777 @ May 7 2008, 14:46) *
С другой стороны, если при их применении нужно тщательное измерение результатов (ведь они так резко меняются от количества вызовов и количества типов) то на фига они нужны - лучше уж быстренько написать что требует заказчик на старом отработанном инструменте
С третьей стороны, если размер так важен, что нужно столь "тщательное измерение результатов", то либо всю программу надо писать на ассемблере, либо это то, что на фотофорумах называют техноонанизмом.

Цитата(777777 @ May 7 2008, 14:46) *
время программиста стоит дороже.
Вы опредедлитесь. А то писать вручную приведение к char* в каждом вызове, писать вручную размеры переменных (ведь макросы тут ни при чём) с шансом где-то ошибиться - это не страшно, подумаешь, время программиста, главное - инструмент старый и отработанный.
Я, кстати, и не тратил бы время на эти измерения, если бы не Ваше столь же голословное, сколь и громкое утверждение.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post

3 страниц V  < 1 2 3
Reply to this topicStart new topic
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 09:38
Рейтинг@Mail.ru


Страница сгенерированна за 0.01441 секунд с 7
ELECTRONIX ©2004-2016