Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Си
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Страницы: 1, 2, 3, 4, 5, 6
Буратино
ЗАДАЧА А
Есть функция (K&R), которая обращает порядок символов в строке. Вот она:


Код
#include <string.h>

void reverse (char s[]) {
   int c, i, j;
  
   for (i = 0, j = strlen(s) - 1; i < j; i++, j--) {
      c = s[i];
      s[i] = s[j];
      s[j] = c;
   }
}


Вопросы:
1. Какие слабые места у данной реализации.
2. Как можно оптимизировать код. И что конкретно это даст.
3. Какие есть варианты реализации функции.

Спасибо!
telix

В коде ошибка поставьте j-- sm.gif
Буратино
Цитата(telix @ Jan 24 2013, 22:37) *
В коде ошибка поставьте j-- sm.gif


да ,сори.

ЗАДАЧА Б
Есть реализация функции перевода "типа" bool в строку.

Код
char *b2s (char b) {
   static char *name[] = {"Out Of Range", "False", "True"};
   return (b < 0 || b > 1) ? name[0] : name [b+1];
}


Вопросы:
1. Какие слабые/ошибочные места у данной реализации.
2. Как можно оптимизировать код. И что конкретно это даст.
3. Какие есть варианты реализации функции.
_Pasha
В смысле AVR, может выглядеть так

CODE
#include <avr/io.h>
#include <string.h>
void reverse(char s[])
{
char *beg = (char *)&(s[0]);
char *end = (char *)&(s[strlen(s)]);
while(beg < end)
{
char c = *beg;
*beg++ = *(--end);
*end = c;
}
}

CODE

82: fc 01 movw r30, r24
84: 01 90 ld r0, Z+
86: 00 20 and r0, r0
88: e9 f7 brne .-6 ; 0x84 <reverse+0x2>
8a: 31 97 sbiw r30, 0x01 ; 1
8c: e8 1b sub r30, r24
8e: f9 0b sbc r31, r25
90: e8 0f add r30, r24
92: f9 1f adc r31, r25
94: dc 01 movw r26, r24
96: 04 c0 rjmp .+8 ; 0xa0 <reverse+0x1e>
98: 8c 91 ld r24, X
9a: 92 91 ld r25, -Z
9c: 9d 93 st X+, r25
9e: 80 83 st Z, r24
a0: ae 17 cp r26, r30
a2: bf 07 cpc r27, r31
a4: c8 f3 brcs .-14 ; 0x98 <reverse+0x16>
a6: 08 95 ret
редактор
По задаче Б.
переменная типа bool принимает значение 0 и !0 (не 0). В зависимости от реализации компиляторе !0 может выглядеть любым целым числом, поэтому "Out Of Range" - некоррекное заявление.
_Pasha
Цитата(редактор @ Jan 25 2013, 08:16) *
По задаче Б.
переменная типа bool принимает значение 0 и !0 (не 0). В зависимости от реализации компиляторе !0 может выглядеть любым целым числом, поэтому "Out Of Range" - некоррекное заявление.

Неправда! Область значений, согласно stdbool.h -это true,false. Отсюда
Код
static const char strue[]="TRUE";
static const char sfalse[]="FALSE";
static const char sndef[]="OUT OF RANGE";
switch(boolean)
{
  case true:
   return &strue;
  case false:
   return &sfalse;
  default:
   return &sndef;
}
msalov
Цитата(_Pasha @ Jan 25 2013, 08:23) *
Неправда! Область значений, согласно stdbool.h -это true,false.

Исходя из того, что в Си bool это всего лишь костыль для пришедших из других языков, и любое не 0-ое значение является истиной для условных операторов, то, ИМХО редактор прав.

Задачу А можно оптимизировать сильнее всего исходя из контекста.
_Pasha
Цитата(gotty @ Jan 25 2013, 08:38) *
и любое не 0-ое значение является истиной для условных операторов, то, ИМХО редактор прав.

biggrin.gif
if(0) - выражение в скобках сейчас == 0
if(!0) - выражение в скобках сейчас == 1
Ы?

Цитата(gotty @ Jan 25 2013, 08:38) *
Задачу А можно оптимизировать сильнее всего исходя из контекста.

Работа непосредственно с двумя указателями выигрывает на любых pic/avr/arm/x51
andrewlekar
В задаче А вижу только один недостаток - это нет проверки на пустую строку. Если длина будет 0, то произойдёт переполнение и запись за пределы строки. По производительности тоже проблем не наблюдаю - можно было бы сделать какой-нибудь ассемблерный SWAP или хотя бы промежуточную переменную поместить в регистр, но это от архитектуры зависит.
В задаче Б всякая жесть. Тип заявлен bool, а передаётся char. Сравнение почему-то с 0 и 1, хотя false и true может быть определена иначе. Нужно сравнивать с настоящими false и true, теми которые используются вашим компилятором.
demiurg_spb
грубовато...
Код
const char* b2s (unsigned char b) {
   static const char* name[] = {"False", "True", "Out Of Range", "Out Of Range"};
   return name[b&3];
}
_Pasha
Цитата(demiurg_spb @ Jan 25 2013, 08:59) *
return name[b&3];

Ага, щаз! А если b например... b=0x0C
msalov
Цитата(_Pasha @ Jan 25 2013, 08:49) *
biggrin.gif
if(0) - выражение в скобках сейчас == 0
if(!0) - выражение в скобках сейчас == 1
Ы?
Я имел ввиду немного другое
Код
    if (42)
    {
        printf("True\n");
    }
    else
    {
        printf("False\n");
    }

Какая ветка условного оператора будет выполнена? Третьего "outofrange" не дано, увы.
_Pasha
Цитата(gotty @ Jan 25 2013, 09:08) *
Я имел ввиду немного другое

Дык это несовместимость типов. laughing.gif Почему к случаям явного приведения int к указателю всегда люди относятся настороженно, а к "притягиванию" bool к char - типа что это нормально?
Примеров привести не могу, у меня не очень богатый сишный опыт. Только анекдот
Цитата
#define true false // собаки, ковыряйтесь теперь сами


sm.gif
demiurg_spb
Цитата(_Pasha @ Jan 25 2013, 10:04) *
Ага, щаз! А если b например... b=0x0C
Ну так я и сказал что грубоватоsm.gif
Код
const char* b2s (unsigned char b) {
   static const char* name[] = {"False", "True", "Out Of Range"};
   return name[(b>1)? 2:b];
}
_Pasha
В армоводческом смысле reverse() с указателями
CODE

0x0800024A B570 PUSH {r4-r6,lr}
0x0800024C 4605 MOV r5,r0
0x0800024E 462C MOV r4,r5
0x08000250 4628 MOV r0,r5
0x08000252 F000F84F BL.W strlen (0x080002F4)
0x08000256 1946 ADDS r6,r0,r5
0x08000258 E007 B 0x0800026A
0x0800025A 7820 LDRB r0,[r4,#0x00]
0x0800025C 1E71 SUBS r1,r6,#1
0x0800025E 460E MOV r6,r1
0x08000260 7809 LDRB r1,[r1,#0x00]
0x08000262 F8041B01 STRB r1,[r4],#0x01
0x08000266 7030 STRB r0,[r6,#0x00]
0x08000268 BF00 NOP
0x0800026A 42B4 CMP r4,r6
0x0800026C D3F5 BCC 0x0800025A
0x0800026E BD70 POP {r4-r6,pc}
msalov
Цитата(_Pasha @ Jan 25 2013, 09:16) *
Дык это несовместимость типов. laughing.gif Почему к случаям явного приведения int к указателю всегда люди относятся настороженно, а к "притягиванию" bool к char - типа что это нормально?

Моё ИМХО: в нынешней реализации Си тип bool не имеет смысла, т.к. операнды операций равно/неравно не приводятся к одному типу (bool), а используются как есть. Вот и получается что 42 != true, а (bool)42 == true в зависимости от компилятора
Herz
Цитата(Буратино @ Jan 24 2013, 22:15) *
Вопросы:
1. Какие слабые/ошибочные места у данной реализации.
2. Как можно оптимизировать код. И что конкретно это даст.
3. Какие есть варианты реализации функции.


Буратино, сообщите нам смысл Ваших вопросов. Что конкретно их породило?
ReAl
Цитата(gotty @ Jan 25 2013, 08:33) *
Моё ИМХО: в нынешней реализации Си тип bool не имеет смысла, т.к. операнды операций равно/неравно не приводятся к одному типу (bool), а используются как есть. Вот и получается что 42 != true, а (bool)42 == true в зависимости от компилятора
(Не понял, почему операнды в выражении (0.5 != 'A') должны приводиться к bool)

Это тоже не должно зависеть от компилятора. Т.е. если у конкретного компилятора «зависит», то он не соответствует стандарту.

В выражении, ну пусть уж (42 != true), операнды используются не «как есть», а приводятся к int.
Была бы она твёрдая — я бы её жевал Было бы 42UL, тогда бы true приводилось бы к unsigned long int :-)

Но зато вот (42 != true) имеет значение true и в
bool b = 5;
в переменную будет занесено 1 даже в C99 c <stdbool.h>, не говоря уже о C++.
Буратино
Цитата(_Pasha @ Jan 24 2013, 23:31) *
В смысле AVR, может выглядеть так

CODE
#include <avr/io.h>
#include <string.h>
void reverse(char s[])
{
char *beg = (char *)&(s[0]);
char *end = (char *)&(s[strlen(s)]);
while(beg < end)
{
char c = *beg;
*beg++ = *(--end);
*end = c;
}

}


А зачем тут скобки?
Код
char *beg = (char *)&(s[0]);
char *end = (char *)&(s[strlen(s)]);
*(--end);


А почему вы пишите
Код
*(--end);

Это с терминатором строки связано?

А какой смысл объявлять и инициализировать "с" внутри операторного блока while?
Как Вы думаете, что передается в функцию: массив или строка? Мне кажется что не очень корректно формальный аргумент сотрица, ну как будет тот-же strlen с массивом то? Может правильнее описать аргумент так: char * s ?

demiurg_spb, мне не очень понравилось. читаемость отвалилась, а скилов не добавилось как по мне.
msalov
Цитата(Буратино @ Jan 25 2013, 11:31) *
Выбираю текст для тату, а что?

Может тогда что из победителе The International Obfuscated C Code Contest выберете sm.gif
MrYuran
Цитата(Буратино @ Jan 25 2013, 12:31) *
А почему вы пишите
Код
*(--end);

Во-первых, пишете (изъявительное наклонение вместо повелительного)
А во-вторых, я однажды написал
* temp ++ ;
имея в виду инкремент значения по указателю, а потом долго не мог понять, почему это "бесполезная операция", с т.з. компилятора.
Буратино
Цитата(MrYuran @ Jan 25 2013, 12:12) *
Во-первых, пишете (изъявительное наклонение вместо повелительного)

а как же жи ,ши через и? sm.gif

Цитата(MrYuran @ Jan 25 2013, 12:12) *
А во-вторых, я однажды написал
* temp ++ ;
имея в виду инкремент значения по указателю, а потом долго не мог понять, почему это "бесполезная операция", с т.з. компилятора.


* temp++ сначала плюсанется указатель, а затем получим значение по плюсанутому указателю ,постави(е)те скобки и все будет так как запланированио, но в нашем то случае именно что и не нужны они! Я так думаю
telix
Я б пример А оптимизировал за счет второго буфера.
То есть не делал тройную пересылку a=>c b=>a c=>b
а однократную b[j--] => a[i++] но при этом a и b это разные массивы
"b" это исходная строка, "a" это пустой массив для записи строки в обратном порядке.
За счет использования второго буфера резко увеличивается скорость собственно операции.
Буратино
Цитата(telix @ Jan 25 2013, 12:29) *
Я б пример А оптимизировал за счет второго буфера.
То есть не делал тройную пересылку a=>c b=>a c=>b
а однократную b[j--] => a[i++] но при этом a и b это разные массивы
"b" это исходная строка, "a" это пустой массив для записи строки в обратном порядке.
За счет использования второго буфера резко увеличивается скорость собственно операции.


по поводу тройной пересылки мы еще поговорим, а вот второй буфер не айс однозначно. во первых b[j--] => a[i++] в 2 раза больше нужно а во вторых место под буфер.
_Pasha
Цитата(Буратино @ Jan 25 2013, 11:31) *
А зачем тут скобки?

А почему вы пишите

А какой смысл объявлять и инициализировать "с" внутри операторного блока while?

Как Вы думаете, что передается в функцию: массив или строка? Мне кажется что не очень корректно формальный аргумент сотрица, ну как будет тот-же strlen с массивом то? Может правильнее описать аргумент так: char * s ?

1. Во-первых, без скобок оно не работало, во вторых, имею недостаток в виде "хронического плавания " в приоритетах, тк Си "не родной язык", по сему не брезгую лишними скобками, тем более, что в 80% случаев это правильный подход.
2. MrYuran ответил, именно после его сообщения, не помню когда и не скажу где sm.gif этот случай навечно впечатался в мозг. А делов-то всего пробел...
3. Как-раз смысл произошел из давних разговоров о свойствах GCC, что чем больше нагрузки на локальные переменные, тем будет правильнее. Листинг AVR это демострирует
4. Прототип функции кривоват, т.к. выпадает из общепринятой практики и заставляет задуматься о языке а не о том, что нужно.
ViKo
Цитата(Буратино @ Jan 25 2013, 12:28) *
* temp++ сначала плюсанется указатель, а затем получим значение по плюсанутому указателю ,постави(е)те скобки и все будет так как запланированио, но в нашем то случае именно что и не нужны они! Я так думаю

Я думаю не так.

Цитата(_Pasha @ Jan 25 2013, 12:38) *
... имею недостаток в виде "хронического плавания " в приоритетах, тк Си "не родной язык", по сему не брезгую лишними скобками, тем более, что в 80% случаев это правильный подход.

Я выписал на листок приоритеты операций, и держу его перед мор над монитором. А иногда еще в текстовые файлы - заметки по проекту - вставляю. И теперь безошибочно пишу что-то вроде a << 4 | b;
А Буратино может набить себе тату - таблицу с приоритетами. Лучшего вряд ли можно посоветовать! rolleyes.gif
Буратино
Цитата(_Pasha @ Jan 25 2013, 12:38) *
1. Во-первых, без скобок оно не работало, во вторых, имею недостаток в виде "хронического плавания " в приоритетах, тк Си "не родной язык", по сему не брезгую лишними скобками, тем более, что в 80% случаев это правильный подход.
2. MrYuran ответил, именно после его сообщения, не помню когда и не скажу где sm.gif этот случай навечно впечатался в мозг. А делов-то всего пробел...
3. Как-раз смысл произошел из давних разговоров о свойствах GCC, что чем больше нагрузки на локальные переменные, тем будет правильнее. Листинг AVR это демострирует
4. Прототип функции кривоват, т.к. выпадает из общепринятой практики и заставляет задуматься о языке а не о том, что нужно.


Хорошо ,мне нравится ваш вариант с указателями давайте его допилим и перейдем ко второй задачке!?
Итак: давайте формальный аргумент заменим на "char * s", это правильнее будет судя по всему. Раз так, то тогда зачем приводить &(s[0]); к (char *) да еще и скобки использовать!? Сначала индекс ,а только потом одноместные унарные!

Код
char *beg = (char *)&(s[0]);
MrYuran
Цитата(Буратино @ Jan 25 2013, 13:28) *
а как же жи ,ши через и? sm.gif

жи это жи, а ше это ше )
Насчет скобок - лучше явно указать.
И самому спокойнее, и читателю понятнее будет.
_Pasha
Цитата(ViKo @ Jan 25 2013, 12:45) *
Я выписал на листок приоритеты операций, и держу его перед мор над монитором. А иногда еще в текстовые файлы - заметки по проекту - вставляю. И теперь безошибочно пишу что-то вроде a << 4 | b;

Дык я это расцениваю(для себя) как write only style sm.gif Тем более, не встречал случаев, когда лишние скобки влияют не результат.
--
Закномерность: чем более пустяковый вопрос, тем оживленнее тема. Насчет замечания Herz. Только штука в том, что здесь из простейшего произрастают интересные вещи. Довольно часто.
Буратино
Цитата(MrYuran @ Jan 25 2013, 12:48) *
жи это жи, а ше это ше )
Насчет скобок - лучше явно указать.
И самому спокойнее, и читателю понятнее будет.


Нет, давайте так: в этих "задачках" сделаем все правильно ,а в жизни будем беспокоится о читателях. Ищу самую правильную и изящную реализацию, хочу вот именно так и не иначе.
demiurg_spb
Цитата(Буратино @ Jan 25 2013, 12:31) *
demiurg_spb, мне не очень понравилось. читаемость отвалилась, а скилов не добавилось как по мне.

Профит есть 2 строчки кода с хорошей читаемостью вместо 6..9 строк кода в другой реализации.
Вы это поймёте, когда будете писать большие программы, в которых становится важна не только выразительность отдельно взятой процедуры, а модуля целиком... Всему своё время.

Цитата(_Pasha @ Jan 25 2013, 09:23) *
Код
static const char strue[]="TRUE";
static const char sfalse[]="FALSE";
static const char sndef[]="OUT OF RANGE";
switch(boolean)
{
  case true:
   return &strue;
  case false:
   return &sfalse;
  default:
   return &sndef;
}
Кстатиsm.gif В этом кусочке кода три ошибки (три лишних символа &).
А вы говорите хорошая читаемость... Чем лаконичнее, тем ИМХО профессиональнее.
ViKo
Цитата(Буратино @ Jan 25 2013, 12:53) *
Ищу самую правильную и изящную реализацию, хочу вот именно так и не иначе.

Если речь идет о первом вопросе, то логичнее не попадать в такую ситуацию. Строки не сами по себе появляются в программе. Вот в момент создания и заносить символы в нужном порядке.
_Pasha
Цитата(Буратино @ Jan 25 2013, 12:48) *
давайте его допилим и

Чо там пилить?
CODE

void reverse(char *s)
{
if(s == NULL) return;
char *end = s;
while(*end) end++;
while(s < end)
{
char c = *s;
*s++ = *(--end);
*end = c;
}
}

Упс... может, они это имели в виду, что при передаче не-указателя не нужно его проверять?
telix
Цитата(Буратино @ Jan 25 2013, 13:35) *
по поводу тройной пересылки мы еще поговорим, а вот второй буфер не айс однозначно. во первых b[j--] => a[i++] в 2 раза больше нужно а во вторых место под буфер.

Я бы поспорил насчет в два раза, и про место под буфер
Так что удачи...
Буратино
Давайте в первом чтении вот такую версию ЗАДАЧИ А от _Pasha обсудим?
Код
#include <string.h>
void reverse ( char *s ) {

   char *beg = s;
   char *end = &s[strlen(s)];
   char c;

   while(beg < end) {
       c = *beg;
      *beg++ = *--end; // благодаря префиксному декременту end терминатор строки '\0' останется на своем месте
      *end = c;
   }
}


_Pasha
Для нелюбителей тройных пересылок есть одна бяка
Код
while(beg < end)
{
  *beg++ = *(--end);
  *end = *beg;
}

Строка "сползает", но ее можно искусственно расширить и передать указ. не на начало, а на s[1]
Бред, в общем случае, но.. если у нас не char а нечто более существенное, пересылки могут доставить
ЗЫ вот только для чего эти сферокони, не пойму sm.gif
ViKo
Цитата(_Pasha @ Jan 25 2013, 13:17) *
Для нелюбителей тройных пересылок есть одна бяка
...
Строка "сползает"

Так вы потеряете первый символ строки... и т.д.
++ инкрементирует указатель после использования.
_Pasha
Цитата(ViKo @ Jan 25 2013, 13:20) *
Так вы потеряете первый символ строки... и т.д.

А не надо его терять. Первый символ !=0 и всё, а сама строка начинается со второго. Ассемблерные заморочки sm.gif
Кстати, такая штуковина со "сползанием и перестановкой" может в графике пригодиться
ViKo
Цитата(_Pasha @ Jan 25 2013, 13:23) *
А не надо его терять. Первый символ !=0 и всё, а сама строка начинается со второго. Ассемблерные заморочки sm.gif
Кстати, такая штуковина со "сползанием и перестановкой" может в графике пригодиться

Т.е. начать переносить на 1 символ левее строки? Тогда в середине появится разрыв. laughing.gif
По-моему, без промежуточной переменной - никак!
Буратино
Вот немного "заоптимизировал". Теперь переменной "с" нет, но есть 3 дополнительные арифметич. действия. Какие есть мысли, соображения? Спасбио!
Код
#include <string.h>
void reverse ( char *s ) {

   char *beg = s;
   char *end = &s[strlen(s)-1];

      do {
         *end -= *beg;
         *beg += *end;
         *end = *beg - *end;
      } while (++beg < --end);
}
_Pasha
Цитата(ViKo @ Jan 25 2013, 13:29) *
Т.е. начать переносить на 1 символ левее строки? Тогда в середине появится разрыв. laughing.gif
По-моему, без промежуточной переменной - никак!

Ага, ошибочка вышла. Да простит меня высокое собрание.

Цитата(Буратино @ Jan 25 2013, 13:53) *
Какие есть мысли, соображения? Спасбио!

На общеприменяемых архитектурах будет хуже. Потому что "лишний" char c есть регистровая переменная. А так - добавляются операции, такие же переменные неявно выделяются компилятором, но самое обидное будет если у нас не char, а long например.
В принципе, вместо + - как у Вас надо бы
Код
поменять местами A,B
A ^= B;
B ^= A;
A ^= B;
Буратино
Цитата(_Pasha @ Jan 25 2013, 14:00) *
Ага, ошибочка вышла. Да простит меня высокое собрание.


На общеприменяемых архитектурах будет хуже. Потому что "лишний" char c есть регистровая переменная. А так - добавляются операции, такие же переменные неявно выделяются компилятором, но самое обидное будет если у нас не char, а long например.
В принципе, вместо + - как у Вас надо бы
Код
поменять местами A,B
A ^= B;
B ^= A;
A ^= B;


с исключающим или мне не очень, хотя красиво конечно a ^= b ^= a ^= b;

Вот еще вариантец, только проверить нужно. Кстати как можно простенькие такие программки потестить? Например в самом ИАРе? Как в отладочное окно выводить результаты всяких printf? Спрашивал однажды и запамятовал к сож(
Код
#include <string.h>
void reverse ( char *s ) {

   char *beg = s;
   char *end = &s[strlen(s)-1];

    do
       *beg += *end - (*end = *beg);
    while (++beg < --end);
}
ViKo
Да, верно, с исключающим или можно обойтись без промежуточной переменной (знал, но забыл). Но это не будет эффективнее, чем использовать еще один регистр.
_Pasha
Цитата(Буратино @ Jan 25 2013, 15:11) *
Вот еще вариантец, только проверить нужно. Кстати как можно простенькие такие программки потестить?

У меня три вивария, с чем работаю, симуляторы
1. C::B + Proteus для аврок - всё в два клика, но создать проект под АРМ - муки творчества, ибо визардов нормальных нету, поэтому
2. Кейл, там тоже элементарно, исключительно из-за stm32 и at91sam7s
3. Mplab
Сыр-бор весь только чтобы глянуть листинг.
Сергей Борщ
QUOTE (Буратино @ Jan 25 2013, 13:11) *
Кстати как можно простенькие такие программки потестить? Например в самом ИАРе? Как в отладочное окно выводить результаты всяких printf?

CODE
C:\user\My documents>echo "#include <stdio.h>\
int main()\
{\
      printf (\"Hello, world\");\
      return 0;\
}\
" > test.c

C:\user\My documents>gcc test.c -o test.exe
C:\user\My documents>test.exe
Hello, world
C:\user\My documents>
ReAl
Цитата(Буратино @ Jan 25 2013, 13:11) *
с исключающим или мне не очень, хотя красиво конечно a ^= b ^= a ^= b;
UB на двух записях в a в переделах sequence point. Правильно так, как было написано сначала, в три строки. Можно записать в две, но это уже неинтересно.

Цитата(Буратино @ Jan 25 2013, 13:11) *
Код
       *beg += *end - (*end = *beg);
Вам так хочется UB-иться?
UB на произвольном порядке вычисления подвыражений (тут возможность записи в *end в скобках в правом аргументе операции вычитания до того, как будет прочитано *end в левом операнде).
ViKo
Что еще за UB? Мы ж так не UBьемся!
Последовательность операций в a ^= b ^= a ^= b; определена точно. Справа налево.
Буратино
что такое UB? что такое в пределах sequence point?
a ^= b ^= a ^= b;
сначала выполнится a ^= b ,затем b ^= a и в конце a ^= b по идее все верно. Нужно проверить.


Код
*beg += *end - (*end = *beg);

тут мне кажется что однозначно от старого *end новое отнимется ,но снова вынужден признать- необходимо проветить
ReAl
Да вроде всегда была определена последовательность вычислений, но не последовательность записи результатов.
Так как значением выражения (a = B) является не «содержимое а после записи», а «значение b приведенное к неквалифицированному типу а».
А (a ^= B) это «то же, что и (a = a ^ B), за исключением того, что a оценивается один раз»
А порядок записи в пределах между точками следования неопределён.

Но что-то меня LWS поколебал...

http://liveworkspace.org/code/Ll7BX$13

gcc по 4.6.3 выдаёт
Цитата
source.cpp:7:20: warning: operation on 'a' may be undefined [-Wsequence-point]

в режимах и C, и C++, gcc 4.7.2 только в режиме C, но не в C++

clang 3.2 доволен всем.

Для меня это новость. Первое (и последнее -- больше так не баловался) предупреждение на a ^= b ^= a ^= b; я получил как бы не от BCC5 уже не помню как давно. Почитал стандарт. Вроде понял :-)

Что касается *beg += *end - (*end = *beg);, то все компиляторы единодушны -- UB (undefined behavior).


Цитата(Буратино @ Jan 25 2013, 14:58) *
что такое UB? что такое в пределах sequence point?
«тут мне кажется», что Вы рано за такие оптимизации взялись :-)

Sequence_point популярно для начала.
_Pasha
Гнаться за мнимым весом строки - позор sm.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.