|
Чем отличаются выражения ?, Приведения типов |
|
|
|
Oct 27 2005, 02:37
|
Группа: Новичок
Сообщений: 5
Регистрация: 23-06-04
Пользователь №: 143

|
Компилятор WINAVR процессор AVR пример взят из firmware WIZNET
uint size; ulong wr_ptr,rd_ptr ; if(wr_ptr >= rd_ptr) size = wr_ptr - rd_ptr ; else size = 0 - rd_ptr + wr_ptr ;
чем отличаются выражения для size и какова последовательность неявных приведений для этого компилятора ?
|
|
|
|
|
 |
Ответов
|
Oct 27 2005, 09:17
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
"0 - rd_ptr" эквиавалентно переводу значения rd_ptr в дополнительный код, при сложении с wr_ptr в результате получается операция вычитания. Суть в том, что значение size получается положительным (разность по модулю) в результате любого ветвления. Кстати, обращаю внимание что переменная size здесь имеет тип unsigned int, а переменные rd_ptr и wr_ptr unsigned long. Если бы константой был не 0, который при любой раскладе = 0, то нужно было бы записывать как size = 0L - rd_ptr + wr_ptr ; или size = (ulong)0 - rd_ptr + wr_ptr ; в противном случае операция была бы не с ulong-овскими числами, а с uint-овскими и результат мог быть неверен. Хотя в этом примере видимо предполагается, что значение size не бывает больше, чем 65535.
|
|
|
|
|
Oct 27 2005, 10:43
|

Частый гость
 
Группа: Свой
Сообщений: 112
Регистрация: 15-10-05
Из: Томск
Пользователь №: 9 680

|
Цитата(rezident @ Oct 27 2005, 16:17) "0 - rd_ptr" эквиавалентно переводу значения rd_ptr в дополнительный код, при сложении с wr_ptr в результате получается операция вычитания. Суть в том, что значение size получается положительным (разность по модулю) в результате любого ветвления. size всегда получается >= 0, т.к. объявлен как uint. И результат будет один и тот же при любом ветвлении. Возможно там хотели написать else size = rd_ptr - wr_ptr; Цитата(rezident @ Oct 27 2005, 16:17) Кстати, обращаю внимание что переменная size здесь имеет тип unsigned int, а переменные rd_ptr и wr_ptr unsigned long. Если бы константой был не 0, который при любой раскладе = 0, то нужно было бы записывать как size = 0L - rd_ptr + wr_ptr ; или size = (ulong)0 - rd_ptr + wr_ptr ; в противном случае операция была бы не с ulong-овскими числами, а с uint-овскими и результат мог быть неверен. Хотя в этом примере видимо предполагается, что значение size не бывает больше, чем 65535. Не важно какого типа константа - uint или ulong. Мы ведь результат присваиваем переменной типа uint. Т.е. старшие биты обрежутся, если sizeof(int)<sizeof(long), и останутся неизменными, если равны.
|
|
|
|
|
Oct 27 2005, 10:54
|

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

|
Цитата(starter48 @ Oct 27 2005, 13:43) size всегда получается >= 0, т.к. объявлен как uint. И результат будет один и тот же при любом ветвлении. Возможно там хотели написать else size = rd_ptr - wr_ptr; Нет, там написано именно то, что хотели, просто так хотели (неподумавши). Там циклический буфер размеорм 1/2/4/8К, "указатели" IP - 32-битные, но в буфере может не более его размера, поэтому для размера (в другом месте - для свободного места в буфере) достаточно 16-битной переменной. Для количества принятых данных вычитать всегда надо из указателя головы указатель хвоста и всё. Цитата(starter48 @ Oct 27 2005, 13:43) Не важно какого типа константа - uint или ulong. Мы ведь результат присваиваем переменной типа uint. Т.е. старшие биты обрежутся, если sizeof(int)<sizeof(long), и останутся неизменными, если равны. Полностью поддерживаю. А поскольку размер данных гарантированно влазит в uint - то всё будет нормально. Это тот же момент, что с таймерами и отсечением интервалов. В смысле Код timer_type_t start = get_timer(); while( (timer_type_t)(get_timer() - start) < delay); это абсолютно правильно и не надо никаких Код timer_type_t start = get_timer(); for(;;) { tymer_type_t end = get_timer(); if( end < start ) // и так далее, как у визнета с указателями }
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Oct 27 2005, 11:52
|

Частый гость
 
Группа: Свой
Сообщений: 112
Регистрация: 15-10-05
Из: Томск
Пользователь №: 9 680

|
Цитата(ReAl @ Oct 27 2005, 17:54) Цитата(starter48 @ Oct 27 2005, 13:43) size всегда получается >= 0, т.к. объявлен как uint. И результат будет один и тот же при любом ветвлении. Возможно там хотели написать else size = rd_ptr - wr_ptr; Нет, там написано именно то, что хотели, просто так хотели (неподумавши). Там циклический буфер размеорм 1/2/4/8К, "указатели" IP - 32-битные, но в буфере может не более его размера, поэтому для размера (в другом месте - для свободного места в буфере) достаточно 16-битной переменной. Для количества принятых данных вычитать всегда надо из указателя головы указатель хвоста и всё. Если циклический буфер, то так писать можно при условии, что размер буфера равен макс. числу в перенной size (65536 для 16bit int). Иначе надо писать size = (wr_ptr - rd_ptr) % BUFFER_SIZE; без всяких if. Или, для оригинального варианта, следует заменить 0 на BUFFER_SIZE: Код uint size; ulong wr_ptr,rd_ptr; if(wr_ptr >= rd_ptr) size = wr_ptr - rd_ptr; else size = BUFFER_SIZE - rd_ptr + wr_ptr; консенсус?
|
|
|
|
|
Oct 28 2005, 01:02
|
Группа: Новичок
Сообщений: 5
Регистрация: 23-06-04
Пользователь №: 143

|
Цитата(starter48 @ Oct 27 2005, 14:52) Цитата(ReAl @ Oct 27 2005, 17:54) Цитата(starter48 @ Oct 27 2005, 13:43) size всегда получается >= 0, т.к. объявлен как uint. И результат будет один и тот же при любом ветвлении. Возможно там хотели написать else size = rd_ptr - wr_ptr; Нет, там написано именно то, что хотели, просто так хотели (неподумавши). Там циклический буфер размеорм 1/2/4/8К, "указатели" IP - 32-битные, но в буфере может не более его размера, поэтому для размера (в другом месте - для свободного места в буфере) достаточно 16-битной переменной. Для количества принятых данных вычитать всегда надо из указателя головы указатель хвоста и всё. Если циклический буфер, то так писать можно при условии, что размер буфера равен макс. числу в перенной size (65536 для 16bit int). Иначе надо писать size = (wr_ptr - rd_ptr) % BUFFER_SIZE; без всяких if. Или, для оригинального варианта, следует заменить 0 на BUFFER_SIZE: Код uint size; ulong wr_ptr,rd_ptr; if(wr_ptr >= rd_ptr) size = wr_ptr - rd_ptr; else size = BUFFER_SIZE - rd_ptr + wr_ptr; консенсус?  Может быть тогда не uint size; ulong wr_ptr,rd_ptr; if(wr_ptr >= rd_ptr) size = wr_ptr - rd_ptr; else size = BUFFER_SIZE - rd_ptr + wr_ptr; а uint size; ulong wr_ptr,rd_ptr; if(wr_ptr >= rd_ptr) size = wr_ptr - rd_ptr; else size = (0xFFFF + 1 ) - rd_ptr + wr_ptr; для понятности
|
|
|
|
|
Oct 28 2005, 10:39
|

Частый гость
 
Группа: Свой
Сообщений: 112
Регистрация: 15-10-05
Из: Томск
Пользователь №: 9 680

|
Цитата(vladsizov @ Oct 28 2005, 08:02) Цитата(starter48 @ Oct 27 2005, 14:52) Цитата(ReAl @ Oct 27 2005, 17:54) Цитата(starter48 @ Oct 27 2005, 13:43) size всегда получается >= 0, т.к. объявлен как uint. И результат будет один и тот же при любом ветвлении. Возможно там хотели написать else size = rd_ptr - wr_ptr; Нет, там написано именно то, что хотели, просто так хотели (неподумавши). Там циклический буфер размеорм 1/2/4/8К, "указатели" IP - 32-битные, но в буфере может не более его размера, поэтому для размера (в другом месте - для свободного места в буфере) достаточно 16-битной переменной. Для количества принятых данных вычитать всегда надо из указателя головы указатель хвоста и всё. Если циклический буфер, то так писать можно при условии, что размер буфера равен макс. числу в перенной size (65536 для 16bit int). Иначе надо писать size = (wr_ptr - rd_ptr) % BUFFER_SIZE; без всяких if. Или, для оригинального варианта, следует заменить 0 на BUFFER_SIZE: Код uint size; ulong wr_ptr,rd_ptr; if(wr_ptr >= rd_ptr) size = wr_ptr - rd_ptr; else size = BUFFER_SIZE - rd_ptr + wr_ptr; консенсус?  Может быть тогда не uint size; ulong wr_ptr,rd_ptr; if(wr_ptr >= rd_ptr) size = wr_ptr - rd_ptr; else size = BUFFER_SIZE - rd_ptr + wr_ptr; а uint size; ulong wr_ptr,rd_ptr; if(wr_ptr >= rd_ptr) size = wr_ptr - rd_ptr; else size = (0xFFFF + 1 ) - rd_ptr + wr_ptr; для понятности Да, если BUFFER_SIZE=64k, но тогда можно написать просто size = wr_ptr - rd_ptr; Но ReAl говорил, что буфер может быть 1/2/4/8k, тогда так писать нельзя. Допустим, wr_ptr = 0;rd_ptr = 1; т.е. циклицеский буфер весь заполнен. Тогда выполнится эта ветка else size = (0xFFFF + 1 ) - rd_ptr + wr_ptr; и size будет равен (uint)((0xFFFF + 1 ) - 1 + 0), т.е. 0xFFFF, т.е. это выражение не учитывает размер буфера. Чтобы этого избежать можно сделать так: Код size = BUFFER_SIZE - rd_ptr + wr_ptr;//size = BUFFER_SIZE - 1
или size = (wr_ptr - rd_ptr) % BUFFER_SIZE; //size = 0xFFFFFFF % BUFFER_SIZE = BUFFER_SIZE - 1
или size = (wr_ptr - rd_ptr) & (BUFFER_SIZE-1); //size = 0xFFFFFFF & (BUFFER_SIZE-1) = BUFFER_SIZE - 1 Скажи plz, где взять исходник оригинальный? А то у меня складывается ощущение, что я чего-то не понимаю  .
|
|
|
|
|
Oct 28 2005, 12:04
|

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

|
Цитата(starter48 @ Oct 28 2005, 13:39) Да, если BUFFER_SIZE=64k, но тогда можно написать просто size = wr_ptr -rd_ptr; Так можно делать при любом буфере размера степени 2. Ещё раз прошу взять листик в клеточку и убедиться самостоятельно. Или убедить меня - привести хотя бы один пример конкретных и корректных значений wr_ptr, rd_ptr и BUFFER_SIZE, при которых size = wr_ptr - rd_ptr; даёт неправильное значение. Под корректными понимаются - BUFFER_SIZE есть (1 shl n) n=0,15; буфер не переполнен. Цитата(starter48 @ Oct 28 2005, 13:39) Но ReAl говорил, что буфер может быть 1/2/4/8k, тогда так писать нельзя. Допустим, wr_ptr = 0;rd_ptr = 1; т.е. циклицеский буфер весь заполнен. Если wr_ptr и rd_ptr такие, то он не заполнен, а очень много раз переполнен (65535 для буфера размером 64К). Ещё раз. wr_ptr и rd_ptr это не столько указатели, сколько IP "номера последовательности". Про то, что они - IP, а не указатели в буфере, я уже писал. Они же 32-битные. Ну подумай сам. Пусть было rd_ptr ==1, wr_ptr == 1 (буфер пуст). Сколько байт надо записать, чтобы 32-битный wr_ptr свернулся в колечко? Я это и имел ввиду под параноидальным вариантом - но и тогда никакие BUFFER_SIZE при вычислении size не нужны. Цитата(starter48 @ Oct 28 2005, 13:39) Чтобы этого избежать можно сделать так: Код size = BUFFER_SIZE - rd_ptr + wr_ptr;//size = BUFFER_SIZE - 1 Вот и залетели. Не поймали переполнение, так как на самом деле в буфер было записано 0xFFFFFFFF байт, в результате которых wr_ptr из 1 превратился в 0. Цитата(starter48 @ Oct 28 2005, 13:39) Код или size = (wr_ptr - rd_ptr) % BUFFER_SIZE; //size = 0xFFFFFFF % BUFFER_SIZE = BUFFER_SIZE - 1
или size = (wr_ptr - rd_ptr) & (BUFFER_SIZE-1); //size = 0xFFFFFFF & (BUFFER_SIZE-1) = BUFFER_SIZE - 1 По этой причине и все эти % млм & не просто не нужны, а вредныЦитата(starter48 @ Oct 28 2005, 13:39) Скажи plz, где взять исходник оригинальный? А то у меня складывается ощущение, что я чего-то не понимаю  . Имеем 1/2/4/8 - килобайтный буфер и 32-битные "указатели", которые наращиваются без учёта самого буфера (IP sequence numbers или как их там). Младшие биты этих величин можно рассматривать как указатели в буфере, старшие - как число "сворачиваний" младших битов по модулю размера буфера.
Сообщение отредактировал ReAl - Oct 28 2005, 12:07
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Oct 28 2005, 13:02
|

Частый гость
 
Группа: Свой
Сообщений: 112
Регистрация: 15-10-05
Из: Томск
Пользователь №: 9 680

|
Цитата(ReAl @ Oct 28 2005, 19:04) Ещё раз. wr_ptr и rd_ptr это не столько указатели, сколько IP "номера последовательности". Про то, что они - IP, а не указатели в буфере, я уже писал. Они же 32-битные. Ну подумай сам. Пусть было rd_ptr ==1, wr_ptr == 1 (буфер пуст). Сколько байт надо записать, чтобы 32-битный wr_ptr свернулся в колечко? Я это и имел ввиду под параноидальным вариантом - но и тогда никакие BUFFER_SIZE при вычислении size не нужны. По этой причине и все эти % млм & не просто не нужны, а вредныИмеем 1/2/4/8 - килобайтный буфер и 32-битные "указатели", которые наращиваются без учёта самого буфера (IP sequence numbers или как их там). Младшие биты этих величин можно рассматривать как указатели в буфере, старшие - как число "сворачиваний" младших битов по модулю размера буфера. Я понял  . Меня в заблуждение ввело название wr_ptr и rd_ptr (ptr=pointer), и то, что ты их указателями назвал. Я думал это индексы для работы с буфером типа buffer[wr_ptr]. Я тормоз. Ты прав, если wr_ptr является счётчиком записанных в буфер с момента старта в буфер байт, то писать надо size = wr_ptr - rd_ptr; а if там просто лишний.
|
|
|
|
Сообщений в этой теме
vladsizov Чем отличаются выражения ? Oct 27 2005, 02:37 NickB Ну так это просто арифметика по модулю 65536 в дан... Oct 27 2005, 08:38        ReAl Цитата(starter48 @ Oct 28 2005, 16:02)Я понял... Oct 28 2005, 13:38    ReAl Цитата(starter48 @ Oct 27 2005, 14:52)Если ци... Oct 28 2005, 05:13  rezident Цитата(starter48 @ Oct 27 2005, 16:43)Возможн... Oct 27 2005, 13:59 ReAl Цитата(vladsizov @ Oct 27 2005, 05:37)Компиля... Oct 27 2005, 09:27
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|