|
Компилятор Gcc или так и должнобыть?, Почему то отказывается выполнять инструкциии |
|
|
|
May 2 2008, 04:17
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 29-12-04
Пользователь №: 1 738

|
Столкнулся с тем что GCC упорно не хочет выполнять следующее, вроде с синтаксисом нет никакого криминала комерческие компиляторы отрабатывают без проблем (Borlad c++ и пр.) не выдавая никаких ошибок и предупреждений
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)++;
В обоих случаях отказывается делать инкремент указателя выдавая ошибку хотя здесь явно указатель приводится к указателю на заданный тип, пробовал указатель описать как указатель на тип char или int ситуация не меняется. С точки зрения синтаксиса вроде всё правильно .. пытался искать в стандарте Ansi C но нашел ничего .. Мож у кого есть какие мысли .. не исключаю что может и я что то делаю не коррекктно.. Конечно эту ситуацию можно обойти... Спасибо.
|
|
|
|
|
 |
Ответов
|
May 5 2008, 12:01
|
Местный
  
Группа: Свой
Сообщений: 359
Регистрация: 9-12-05
Пользователь №: 12 034

|
А если так: Код unuon { char *pc; int *pi; long *pl; } u;
u.pc = &buff;
char c = *u.pc++; int i = *u.pi++; long l = *u.pl++;
|
|
|
|
|
May 6 2008, 18:45
|

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

|
Цитата(777777 @ May 6 2008, 22:53)  Так можно. Только зачем? Языки высокого уровня придумываются для того, чтобы избегать низкоуровневых работ, а также для обнаружения большинства ошибок на этапе компиляции. А чего мы добиваемся подобной конструкцией? Вы уже несколько раз это повторили. А нельзя ли привести пример того, как такое делается на языках высокого уровня? Скажем, вы принимаете сериализованный список переменных разного типа. То есть, принятый вами буфер выглядит следующим образом: [число_переменных_в_пакете][номер_переменной1][переменная1][номер_переменной2][п еременная2]...[номер_переменнойN][переменнаяN]. В зависимости от номера переменной её тип может быть int, char, double, long int. Научите, как это делается на языках высокого уровня?
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
May 7 2008, 04:18
|

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

|
Цитата(AHTOXA @ May 6 2008, 22:45)  А нельзя ли привести пример того, как такое делается на языках высокого уровня? Скажем, вы принимаете сериализованный список переменных разного типа. То есть, принятый вами буфер выглядит следующим образом: [число_переменных_в_пакете][номер_переменной1][переменная1][номер_переменной2][п еременная2]...[номер_переменнойN][переменнаяN]. В зависимости от номера переменной её тип может быть int, char, double, long int. Научите, как это делается на языках высокого уровня? Очень просто. (Правда, номер переменной здесь не нужен - обычно порядок определяет назначение переменной). Можно написать функцию read(void* buf, uint8_t size) которая "принимает" (неважно откуда) данные размера size. Тогда мы пишем: int var1; char var2; double var3; long var4; read(&var1, sizeof(var1)); read(&var2, sizeof(var2)); read(&var3, sizeof(var3)); read(&var4, sizeof(var4)); или еще проще: struct VAR { int var1; char var2; double var3; long var4; } var; read(&var, sizeof(var)); Только здесь надо позаботиться чтобы переменные в стуктуре были выровнены побайтно. А самой функции read нет необходимости знать о типах - она читает только заданное количество байт. Содержимое функции read зависит от того, откуда ей принимать данные, в любом случае ей придется инкрементировать указатель *buf. Если компилятор допускает ++ для типа void* и увеличивает его именно на 1, то такой код годится, если нет (как того требует стандарт) - то прототип функции должен быть read(char* buf, uint8_t size), но тогда при обращении к ней нужно приводить тип буфера к char*
|
|
|
|
|
May 7 2008, 04:54
|

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

|
Цитата(777777 @ May 7 2008, 10:18)  Очень просто. (Правда, номер переменной здесь не нужен - обычно порядок определяет назначение переменной). Номер переменной здесь нужен потому, что в пакете могут быть произвольные переменные. Например, передаются только изменившиеся параметры - это сильно экономит трафик. Но не суть. Цитата Можно написать функцию read(void* buf, uint8_t size) которая "принимает" (неважно откуда) данные размера size. Собственно весь вопрос и заключался в том, как должна быть написана эта функция. Вы функцию не привели, и идеи ваши никуда не ушли в сторону от банальной арифметики с указателями. Цитата Содержимое функции read зависит от того, откуда ей принимать данные, в любом случае ей придется инкрементировать указатель *buf. Если компилятор допускает ++ для типа void* и увеличивает его именно на 1, то такой код годится, если нет (как того требует стандарт) - то прототип функции должен быть read(char* buf, uint8_t size), но тогда при обращении к ней нужно приводить тип буфера к char* Не вижу здесь никакого особого "высокоуровневого" подхода.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
May 7 2008, 05:00
|

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

|
Цитата(AHTOXA @ May 7 2008, 08:54)  Собственно весь вопрос и заключался в том, как должна быть написана эта функция. Вы функцию не привели, и идеи ваши никуда не ушли в сторону от банальной арифметики с указателями. Вы тоже не объяснили откуда плучаются данные. void read(char* p, uint8_t n) { while(n--) *p++ = getchar(); } Каков вопрос, таков ответ  А вообще, вопрос надо задавать более широко: что требуется в конечном итоге? Тогда, возможно, отпадет даже сама необходимость решать этот частный вопрос.
Сообщение отредактировал 777777 - May 7 2008, 05:02
|
|
|
|
|
May 7 2008, 05:03
|

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

|
Цитата(777777 @ May 7 2008, 11:00)  Вы тоже не объяснили откуда плучаются данные. А какая разница? Цитата void read(char* p, uint8_t n) { while(n--) *p++ = getchar(); } Спасибо, теперь я наконец-таки узнал, как надо писать на языке высокого уровня
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
May 7 2008, 06:48
|

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

|
Цитата(AHTOXA @ May 7 2008, 08:03)  Спасибо, теперь я наконец-таки узнал, как надо писать на языке высокого уровня Можно я чуток поправлю? Любой указатель приводится к 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(); } Еще можно предположить, что размер переменной не может быть равным нулю. Тогда: Код void read(void* pDst, uint8_t size) { uint8_t *p = (uint8_t*)pDst; do *p++ = getchar(); while (--size); } Ну и отсюда всего один шаг до С++: Код template <typename T> void read(T & Dst) { uint8_t *p = (uint8_t*)&Dst; do *p++ = getchar(); while (--size); }
read(var1); read(var2); read(var3); Или, если экономим код, то Код void read(void* pDst, uint8_t size) { uint8_t *p = (uint8_t*)pDst; do *p++ = getchar(); while (--size); } template <typename T> void read(T & Dst) { read(&T, sizeof(T)); }
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
May 7 2008, 07:38
|

Профессионал
    
Группа: Участник
Сообщений: 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)); } Если уж нас заботит экономия кода, то с шаблошами лучше не связываться...
|
|
|
|
|
May 7 2008, 09:30
|

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

|
Цитата(777777 @ May 7 2008, 10:38)  Если уж нас заботит экономия кода, то с шаблошами лучше не связываться...  Если нас заботит экономия кода, то любой иснтрумент надо применять аккуртано. Многие монстроидальные результаты нынешнего софтостроения связаны не с примененеим С++ вообще или шаболнов в частности, а с бездумным "оттянул-уронил". Я бы, может, и не влез, если бы не эта последняя фраза, которую я процитировал первой. Цитата(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)  Если уж нас заботит экономия кода, то с шаблошами лучше не связываться...  Вернёмся. Для более правдоподобного сравнивания я в каждом варианте прочту каждый вид переменной по нескольку раз. Чистый С, "без никаких латинских примесей" 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); }
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
May 7 2008, 11:46
|

Профессионал
    
Группа: Участник
Сообщений: 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)  Для более правдоподобного сравнивания я в каждом варианте прочту каждый вид переменной по нескольку раз. Я извиняюсь, но это сделано не для "более правдоподобного сравнивания", а для того, чтобы вариант с шаблонами оказался короче  Достаточно оставить 5 чтений вместо 6 - и результат резко меняется. Но и с шестью чтениями, стоит добавить еще один тип данных - и он вновь окажется длинее за счет появления еще одной инстанцированной функции. Цитата(ReAl @ May 7 2008, 13:30)  Если нас заботит экономия кода, то любой иснтрумент надо применять аккуртано. Многие монстроидальные результаты нынешнего софтостроения связаны не с примененеим С++ вообще или шаболнов в частности, а с бездумным "оттянул-уронил". С другой стороны, если при их применении нужно тщательное измерение результатов (ведь они так резко меняются от количества вызовов и количества типов) то на фига они нужны - лучше уж быстренько написать что требует заказчик на старом отработанном инструменте - время программиста стоит дороже.
Сообщение отредактировал 777777 - May 7 2008, 11:47
|
|
|
|
Сообщений в этой теме
Олег. Компилятор Gcc или так и должнобыть? May 2 2008, 04:17 forever failure Видимо имеется ввиду это:
warning: use of cast exp... May 2 2008, 04:43 777777 Цитата(Олег. @ May 2 2008, 08:17) Столкну... May 2 2008, 05:46 zltigo Цитата(777777 @ May 2 2008, 07:46) Борлан... May 2 2008, 07:13 umup попробуйте так :
Код b[0] = *((u... May 2 2008, 06:48 ReAl Цитата(umup @ May 2 2008, 09:48) попробуй... May 2 2008, 08:33 ReAl Цитата(Олег. @ May 2 2008, 07:17) вроде с... May 2 2008, 08:08 umup ЦитатаА вот этого не надо, если в оригинальном вар... May 2 2008, 08:23 zltigo Цитата(umup @ May 2 2008, 10:23) какая ?
... May 2 2008, 08:38  aesok Цитата(zltigo @ May 2 2008, 12:38) Без ... May 2 2008, 08:44   zltigo Цитата(aesok @ May 2 2008, 10:44) А если ... May 2 2008, 08:48  ReAl Цитата(zltigo @ May 2 2008, 11:38) Имя ко... May 2 2008, 09:02   Олег. Я пробовал в Borland C++ Builder6, там всё проходи... May 2 2008, 09:36    777777 Цитата(Олег. @ May 2 2008, 13:36) Не искл... May 2 2008, 14:58     Олег. Да Вы в общем то правы. Да я пишу на С но всегда к... May 2 2008, 15:55      777777 Цитата(Олег. @ May 2 2008, 19:55) Да Вы в... May 2 2008, 16:09   zltigo Цитата(ReAl @ May 2 2008, 11:02) gcc в да... May 2 2008, 09:41 umup можно так :
Код b[0] = *(unsigned long... May 2 2008, 10:30 Олег. Да конечно так можно.. Я понимаю.. До меня дошло ч... May 2 2008, 11:52 Andreas1 поскольку только осваиваюсь в сях, а ситуация инте... May 2 2008, 17:12 AHTOXA Цитата(Andreas1 @ May 2 2008, 23:12) И де... May 2 2008, 17:35 ReAl Цитата(Andreas1 @ May 2 2008, 20:12) поск... May 2 2008, 19:15           ReAl Цитата(777777 @ May 7 2008, 14:46) Все эт... May 7 2008, 12:59         Сергей Борщ Цитата(777777 @ May 7 2008, 10:38) А вот ... May 7 2008, 09:51        AHTOXA Цитата(Сергей Борщ @ May 7 2008, 12:48) М... May 7 2008, 07:56 alexander55 Цитата(Олег. @ May 2 2008, 08:17) unsigne... May 7 2008, 10:02
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|