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

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

|
Да конечно так можно.. Я понимаю.. До меня дошло что к моменту взятия постинкремента тип к которому было приведение уже теряется и поэтому операция постинкремента уже не корректна. Интересно то что в Borlande приведение типа видимо сохраняется и далее постинкремент работает правильно в соответствии с приведённым типом.. Не буду спорить правильно ли это или нет но влюбом случае такой приём надо избегать.. я не собираюсь использовать это в коде проекта...  Просто столкнулся с разным поведением компиляторов при разборе синтаксиса пусть даже и не корректного..В любом случае благодарю за обсуждение. Спасибо.
|
|
|
|
|
May 2 2008, 14:58
|

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

|
Цитата(Олег. @ May 2 2008, 13:36)  Не исключаю что косяк в моей голове.. А почему бы не сделать сразу этот указатель на unsigned long - и не придется ничего преобразовывать? Цитата(Олег. @ May 2 2008, 13:36)  Просто иногда очень удобено описать указатель на массив как void* и по ходу дела приводить и его к разным типам разыменовывая содержимое буферного массива чтобы не создавать кучу разных указателей на разные типы данных.. Ты пишешь на Си, а думаешь на ассемблере, и пытаешься помочь компилятору. Сделай над собой усилие и забудь об ассемблере - напиши программу, думая только об алгоритме. С твоей стороны помощь компилятору может заключаться в том, чтобы локализовать использование каждой переменной - объявлять ее только в той области видимости, где она используется, и минимизировать количество глобальных переменных.
|
|
|
|
|
May 2 2008, 15:55
|
Участник

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

|
Да Вы в общем то правы. Да я пишу на С но всегда копаюсь в скомпилированом коде ассемблера. Как ни крути ну сильна привычка и любовь к железу.. пока не могу оторваться ибо до этого много работал на ассемблере. С приобретением опыта программирования на С думаю это пройдет но пока стараюсь и учусь. Спасибо.
|
|
|
|
|
May 2 2008, 17:12
|
Местный
  
Группа: Свой
Сообщений: 446
Регистрация: 12-03-06
Из: Москва
Пользователь №: 15 142

|
поскольку только осваиваюсь в сях, а ситуация интересная, посоветовался с опытным человеком Цитата извините, но эта попытка инкрементировать временный объект.... *((T*) p)++ это на самом деле T* tmp = (T*) p; *tmp++ ......Они все таки временные переменные сделали r-value... а по старому стандарту это все законные выражения....
правильно это делается так *(*(T**)&p)++ И действительно b[0] = *(*(unsigned long int **)&ptr)++; не вызвал ошибки и , судя по листингу, правильно инкрементировал ptr. Правда пока не понял в чем разница
|
|
|
|
|
May 2 2008, 17:35
|

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

|
Цитата(Andreas1 @ May 2 2008, 23:12)  И действительно b[0] = *(*(unsigned long int **)&ptr)++; не вызвал ошибки и , судя по листингу, правильно инкрементировал ptr. Правда пока не понял в чем разница  Это то же, что предлагал ReAl немного выше. Разница в том, что в этом случае временный объект - указатель на наш указатель, и модифицируется не он (не временный объект), а то, на что он указывает (о как мощно задвинул:-) ) В принципе это тоже не комильфо, но работает.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
May 2 2008, 19:15
|

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

|
Цитата(Andreas1 @ May 2 2008, 20:12)  поскольку только осваиваюсь в сях, а ситуация интересная, посоветовался с опытным человеком Что значит "по старому стандарту"? По K&R первого издания, являвшимся "стандартом де-факто", но не "де-юре"? Я же привёл выше цитату из стандарта 1989 года про то, что cast не есть lvalue. Другое дело, что многие компиляторы до конца 90-ых (а борлданд - так похоже и до середины 2010-ых :-) ) так и не удосужились привести себя в соответствие стандарту 1989 года, как и сейчас не все и не всё делают согласно стандарту 1999 года... Цитата(AHTOXA @ May 2 2008, 20:35)  Это то же, что предлагал ReAl немного выше. Это то де по сути, но прозрачнее записано. То, что написал я - можно подрихтовать, вставив вместо sizeof свой макрос, который как-то корректирует размер - например, в зависимости от параметра, задающего выравнивание. У того же борланда, насколько я помню, так сделан макрос (а не __builtin) VA_ARG (stdarg.h).
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
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)
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|