Перейти к содержанию
    

с исключающим или мне не очень, хотя красиво конечно a ^= b ^= a ^= b;
UB на двух записях в a в переделах sequence point. Правильно так, как было написано сначала, в три строки. Можно записать в две, но это уже неинтересно.

 

       *beg += *end - (*end = *beg);

Вам так хочется UB-иться?

UB на произвольном порядке вычисления подвыражений (тут возможность записи в *end в скобках в правом аргументе операции вычитания до того, как будет прочитано *end в левом операнде).

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что еще за UB? Мы ж так не UBьемся!

Последовательность операций в a ^= b ^= a ^= b; определена точно. Справа налево.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

что такое UB? что такое в пределах sequence point?

a ^= b ^= a ^= b;

сначала выполнится a ^= b ,затем b ^= a и в конце a ^= b по идее все верно. Нужно проверить.

 

 

*beg += *end - (*end = *beg);

тут мне кажется что однозначно от старого *end новое отнимется ,но снова вынужден признать- необходимо проветить

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да вроде всегда была определена последовательность вычислений, но не последовательность записи результатов.

Так как значением выражения (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).

 

 

что такое UB? что такое в пределах sequence point?
«тут мне кажется», что Вы рано за такие оптимизации взялись :-)

 

Sequence_point популярно для начала.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Хех.

6.5.16 Assignment operators

Syntax

assignment-expression:

conditional-expression

unary-expression assignment-operator assignment-expression

assignment-operator: one of

= *= /= %= += -= <<= >>= &= ^= |=

...

 

Semantics

3 An assignment operator stores a value in the object designated by the left operand. An assignment expression has the value of the left operand after the assignment, but is not an lvalue. The type of an assignment expression is the type of the left operand unless the left operand has qualified type, in which case it is the unqualified version of the type of the left operand. The side effect of updating the stored value of the left operand shall occur between the previous and the next sequence point.

 

5.17 Assignment and compound assignment operators

...

In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression.

Это они сводят поведение assignment operators для POD к поведению перегруженных операторов для классов (которые есть функции и уж точно завершат запись до возврата значения)?

 

Свежий стандарт C (не С++) у кого-то есть? Недавно и C обновили, не только С++

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Наверное, цитата по ссылке

At the end of a full expression. This category includes expression statements (such as the assignment a=b;)

говорит, что любое ^= создает sequence point.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не говорит. В "например" определяющей является точка с запятой, заканчивающая утверждение, а не присваивающий оператор, являющийся вместе со своими операндами выражением.

6.8 Statements and blocks

Syntax

1 statement:

labeled-statement

compound-statement

expression-statement

selection-statement

iteration-statement

jump-statement

4 A full expression is an expression that is not part of another expression or of a declarator.

Each of the following is a full expression: an initializer; the expression in an expression

statement; the controlling expression of a selection statement (if or switch); the

controlling expression of a while or do statement; each of the (optional) expressions of

a for statement; the (optional) expression in a return statement. The end of a full

expression is a sequence point.

6.8.3 Expression and null statements

Syntax

expression-statement:

expressionopt;

Т.е. expression в данному случае превращается в full expression путём участия в expression statement при помощи завершения символом

;

т.е.:

a = b = c = d; Это один expression-statement, превращает в full-expression всё a = b = c = d

Cостоящее из нескольких subexpression.

 

Может, в С++, особенно в C++11, что-то и не так, я туда ещё так не вчитывался.

Какие-то моменты, undefined в C, стали unspecified в C++, с этими их тонкостями ещё пойди разберись.

 

Да, кстати, я не подчеркнул отдельно

как можно простенькие такие программки потестить?

Вот ответ, разными компиляторами можно:

 

http://liveworkspace.org

 

Причём не только C/C++.

В ответ на кусок кода вся диагностическая выдача компилятора (в зависимости от ключей) и, при создании исполняемого файла, выдача на stdout

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот еще вариант. В основе смелая идея (уже ранее высказанная) о том чтоб испоьзовать буфер, но я немного переосмыслил это дело :)

 

#include <stdio.h>
#define MAX_LEN 100

char * reverse ( char *s ) {
   static char buf[MAX_LEN];
   char *buf_pointer = &buf[MAX_LEN-1];

   while ( (*buf_pointer-- = *s++) )  // компилятор попросил о 2х скобках, ну раз ему так легче, то пусть будут:)
;
   return buf_pointer+2;
}

int main() {
   char s[]= "Hello World!";
   printf("%s\n", reverse (s) ); 

}

 

stdout:
!dlroW olleH

 

Итак, я считаю что с задачей А мы справились. Плавно переходим к задаче Б..

 

Задача Б

В этой реализации мне не нравится, что в случае дефолта сначала проверится один кейс, затем другой и только потом собственно выполнится подходящее действие! Что если нужно например месяца из чисел в названия переводить или там справочные данные какие?

Потом мне непонятно почему нужно static const char strue[]="бла-бла-бла"; делать!? Это в смысле что строки в памяти программ расположатся? Как с доступом к таким значениям? не будет страдать производительность?

 

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;
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Итак, я считаю что с задачей А мы справились.

Для таких программ потом и пишут заплатки на тему переполнения какого-нить буфера.

Потом мне непонятна почему нужно static const char strue[]="бла-бла-бла"; делать!?

static - чтобы можно было вернуть из функции указатель на что-то вменяемое, const - считайте просто правилом хорошего тона.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для таких программ потом и пишут заплатки на тему переполнения какого-нить буфера.

 

static - чтобы можно было вернуть из функции указатель на что-то вменяемое, const - считайте просто правилом хорошего тона.

 

Для этой задачи оптимальным наверное будет сочетание двух подходов: в случае если длина строки не более чем MAX_LEN использовать один подход, если больше - второй, и менять данные прямо по месту. Я пока еще не придумал как красиво пофиксить переполнение буфера ибо нужно на каждой итерации проверять условие достижения конца буфера, а мне не оч. такой вариант.

 

 

Вот у меня тоже static, но при этом данные в массиве указателей описаны внутри функции, вроде так логичнее получается ,зачем выносить их наружу меняя область действия?

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Итак, я считаю что с задачей А мы справились.
Поосторожнее… А то сейчас набегут спецы, которые сначала скажут, что возвращать указатель на внутренний статический буфер нельзя, потом скажут, что они имели ввиду, что оно-то можно, но глюкодром. А на вопрос, чем именно

const char *foo()
{
    static char buf[10];
    ...
    return buf;
}

глюкодромее

const char *moo()
{
    return "bla-bla-bla";
}

просто не будут отвечать по существу.

Недостаток у способа один:

char str1[] = "String 1";
char str2[] = "String 2";
printf("%s %s\n", reverse(str1), reverse(str2));

Впрочем, для таких случаев мои функции подобного типа принимают второй аргумент (со значением по умолчанию в C++), которым программа, имеющая желание в одни заход получить несколько строк, обязан апередать буфер достаточного размера:

const char *reverse(const char *src, char *tmpbuf = 0)
{
    static char inernal_buf[сикоку_не_жаль];
    if (!tmpbuf) tmpbuf = internal_buf;
    …
    return tmpbuf; // или что там надо по алгоритму
}

В итоге в большинстве случаев вызывается reverse(some_string); (второй аргумент по умолчанию подставляется 0), и только в отдельных случаях подставляется доп. буфер.

 

Однако задача в некотором смысле не решена и не может быть решена без уточнения условий и целей.

Например, если цель — скорость, а строки преимущественно «достаточно длинные», а процессор Cortex-M3 или другой, имеющий команду реверся байтов в 32-битном слове (i486+), то стоит подумать о зачитывании по 32 бита, реверсе порядка байтов соответствующей командой и т.п. Соответственно, с выделением места под буфер кратно 4 байтам + под концевой 0, спецобработкой хвоста из 1..3 символов и возвратом указателя на tmp_buf с нужным смещением.

«Если Вы не указали цель оптимизации, то Вам всё равно, как писать код» © Чеширсикй Кот – программист.

 

Это в смысле что строки в памяти программ расположатся? Как с доступом к таким значениям? не будет страдать производительность?
По простому const объекты расположатся в памяти программ только у тех процессоров, у которых память программ и память данных находятся в одном и том же адресном пространстве.

(чтобы не повторяться)

 

А в таком случае производительность, в первом приближении, не пострадает.

 

 

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

 

 

 

Вот у меня тоже static, но при этом данные в массиве указателей описаны внутри функции, вроде так логичнее получается ,зачем выносить их наружу меняя область действия?

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

Да, лучше внутри функции.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я надеюсь, высказывание касается только того, что перед реверсом либо в процессе оного не проверияется длина строки.

Безусловно.

Т.к. в условии задачи не сказано, что исходная строка должна сохраниться, я бы делал реверс на месте. Цена вопроса - один strlen(). (оно, конечно, не спасёт, если строка вдруг окажется без '\0')

Само по себе наличие промежуточного буфера фиксированного размера к ошибкам переполнения буфера не приводит.

К переполнению, естественно, не приведёт. Но если память (опять же вдруг) закончится...

 

За жисть. У меня K&R был первого советского издания (в мягком переплёте, голубая обложка), не помню в нём таких упражнений. Хотя, может опять склероз буйствует.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Т.к. в условии задачи не сказано, что исходная строка должна сохраниться, я бы делал реверс на месте. Цена вопроса - один strlen(). (оно, конечно, не спасёт, если строка вдруг окажется без '\0')
Так в том-то и дело, что в условии задачи не сказано ничего (см. выше про Чеширского Кота – программиста). Как я говорил дочери, когда в школе на информатике пошёл паскаль, — программу можно оптимизировать на скорость написания, на простоту отладки, на скорость выполнения, на минимальный размер, на скорость понимания другим человеком, …

«Множество чего? Просто множество!» (что-то меня на Алису потянуло) «просто оптимизировать» невозможно.

 

За жисть. У меня K&R был первого советского издания (в мягком переплёте, голубая обложка), не помню в нём таких упражнений. Хотя, может опять склероз буйствует.
У меня был K&R, любовно кем-то подготовленный (фигурные скобки сделаны из круглых с надпечаткой поверх минусом, ключевые слова двойной печатью, …) и напечатанный на барабанном АЦПУ, переплетённый в переплётной мастерской (кажись, в один заказ с дипломной работй жены, тогда это 1987 год). Тоже таких упражнений не помню :-)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня K&R был первого советского издания (в мягком переплёте, голубая обложка), не помню в нём таких упражнений. Хотя, может опять склероз буйствует.

Во втором издании (в мягком переплете, белая обложка, голубая буква С) есть упражнения по переворачиванию строки.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...