Использование оператора запятой C [дубликат]

Это - текущая установка в проекте, который мы разрабатываем:

  • MavenCentral
  • ObjectWeb
  • JBoss Maven2
  • и некоторые снимки (см. ниже)

    <repository>
        <id>MavenCentral</id>
        <name>Maven repository</name>
        <url>http://repo1.maven.org/maven2</url>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>objectweb</id>
        <name>Objectweb repository</name>
        <url>http://maven.objectweb.org/maven2</url>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>jboss</id>
        <name>JBoss Maven2 repository</name>
        <url>http://repository.jboss.com/maven2/</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
        <releases>
            <enabled>true</enabled>
        </releases>
    </repository>
    <repository>
        <id>glassfish</id>
        <name>Glassfish repository</name>
        <url>http://download.java.net/maven/1</url>
        <layout>legacy</layout>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>apache.snapshots</id>
        <name>Apache Snapshot Repository</name>
        <url>
            http://people.apache.org/repo/m2-snapshot-repository
        </url>
        <releases>
            <enabled>false</enabled>
        </releases>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>ops4j.repository</id>
        <name>OPS4J Repository</name>
        <url>http://repository.ops4j.org/maven2</url>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>Codehaus Snapshots</id>
        <url>http://snapshots.repository.codehaus.org/</url>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
        <releases>
            <enabled>false</enabled>
        </releases>
    </repository>
    
88
задан pythonic metaphor 27 January 2016 в 22:03
поделиться

17 ответов

Язык C (как и C ++) исторически представляет собой смесь двух совершенно разных стилей программирования, которые можно назвать «программированием операторов» и «программированием выражений». Как вы знаете, каждый процедурный язык программирования обычно поддерживает такие фундаментальные конструкции, как секвенирование и ветвление (см. Структурированное программирование ). Эти фундаментальные конструкции представлены в языках C / C ++ в двух формах: одна для программирования операторов, другая для программирования выражений.

Например, когда вы пишете свою программу в терминах операторов, вы можете использовать последовательность операторов, разделенных ; . Если вы хотите выполнить ветвление, используйте операторы if . Вы также можете использовать циклы и другие виды операторов передачи управления.

В программировании выражений вам также доступны те же конструкции. Именно здесь в игру вступает оператор , . Оператор , не что иное, как разделитель последовательных выражений в C, то есть оператор , в программировании выражений выполняет ту же роль, что и , выполняет в программировании операторов. Ветвление в программировании выражений осуществляется с помощью оператора ?: и, в качестве альтернативы, с помощью свойств вычисления короткого замыкания операторов && и || . (У программирования выражений нет циклов. И чтобы заменить их рекурсией, вам придется применить программирование операторов.)

Например, следующий код

a = rand();
++a;
b = rand();
c = a + b / 2;
if (a < c - 5)
  d = a;
else
  d = b;

, который является примером традиционного программирования операторов, может быть переписан в терминах программирования выражений как

a = rand(), ++a, b = rand(), c = a + b / 2, a < c - 5 ? d = a : d = b;

, или как

a = rand(), ++a, b = rand(), c = a + b / 2, d = a < c - 5 ? a : b;

, или

d = (a = rand(), ++a, b = rand(), c = a + b / 2, a < c - 5 ? a : b);

, или

a = rand(), ++a, b = rand(), c = a + b / 2, (a < c - 5 && (d = a, 1)) || (d = b);

Само собой разумеется, на практике программирование операторов обычно производит гораздо более читаемый код C / C ++, поэтому мы обычно используем программирование выражений в очень хорошо измеренных и ограниченных количествах. Но во многих случаях это бывает удобно. И граница между приемлемым и неприемлемым в значительной степени является вопросом личных предпочтений и способности распознавать и читать устоявшиеся идиомы.

В качестве дополнительного примечания: сам дизайн языка, очевидно, приспособлен к утверждениям. . Операторы могут свободно вызывать выражения, но выражения не могут вызывать операторы (кроме вызова предопределенных функций). Эта ситуация довольно интересным образом изменена в компиляторе GCC, который поддерживает так называемые «выражения операторов» в качестве расширения (симметрично «операторам выражений» в стандарте C). «Выражения операторов» позволяют пользователю напрямую вставлять код на основе операторов в выражения, точно так же, как они могут вставлять код на основе выражений в операторы в стандарте C.

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

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

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

97
ответ дан 24 November 2019 в 07:28
поделиться

Единственный раз, когда я видел оператор , , используемый вне цикл for должен был выполнить задание в тернарном операторе. Это было давно, поэтому я не могу вспомнить точное выражение, но это было примерно так:

int ans = isRunning() ? total += 10, newAnswer(total) : 0;

Очевидно, что ни один здравомыслящий человек не стал бы писать подобный код, но автор был злым гением, создавшим операторы c на основе сгенерированного кода ассемблера , а не читабельность.

0
ответ дан 24 November 2019 в 07:28
поделиться

Ниже приводится определение типа-класса Монады .

class  Monad m  where

    (>>=)       :: forall a b. m a -> (a -> m b) -> m b
    (>>)        :: forall a b. m a -> m b -> m b
    return      :: a -> m a
    fail        :: String -> m a

    m >> k      = m >>= \_ -> k
    fail s      = error s

Каждый тип-экземпляр класса-типа Монада определяет свою собственную >> = функция. Вот пример из type-instance Maybe :

instance  Monad Maybe  where

    (Just x) >>= k      = k x
    Nothing  >>= _      = Nothing

    (Just _) >>  k      = k
    Nothing  >>  _      = Nothing

    return              = Just
    fail _              = Nothing

Как мы видим, потому что версия Maybe >> = специально определена для понимания экземпляр типа Maybe , и поскольку он определен в месте, имеющем законный доступ к данным Может быть, конструкторы данных Ничего и Просто , Может быть версия >> = может разворачивать a в Может быть и передавать их через .

Чтобы проработать пример, мы могли бы взять:

0
ответ дан 24 November 2019 в 07:28
поделиться

Я использовал его для макроса, чтобы "назначить значение любого типа для выходного буфера, на который указывает символ *, а затем увеличить указатель на необходимое количество байтов », например:

#define ASSIGN_INCR(p, val, type)  ((*((type) *)(p) = (val)), (p) += sizeof(type))

Использование оператора запятой означает, что макрос может использоваться в выражениях или в качестве операторов по желанию:

if (need_to_output_short)
    ASSIGN_INCR(ptr, short_value, short);

latest_pos = ASSIGN_INCR(ptr, int_value, int);

send_buff(outbuff, (int)(ASSIGN_INCR(ptr, last_value, int) - outbuff));

Это немного уменьшило повторяющийся набор текста, но вы должны быть осторожны, чтобы он не стал слишком нечитабельным.

Пожалуйста, посмотрите мою слишком длинную версию этого ответа здесь .

0
ответ дан 24 November 2019 в 07:28
поделиться

Учитывая цитату @Nicolas Goy из стандарта, то похоже, что вы могли бы написать однострочник для циклов, например:

int a, b, c;
for(a = 0, b = 10; c += 2*a+b, a <= b; a++, b--);
printf("%d", c);

Но боже мой, вы действительно хотите сделать свой C код еще что-то неясное?

4
ответ дан 24 November 2019 в 07:28
поделиться

Я часто использую его для запуска функции статического инициализатора в некоторых файлах cpp, чтобы избежать проблем с ленивой инициализацией классических синглтонов:

void* s_static_pointer = 0;

void init() {
    configureLib(); 
    s_static_pointer = calculateFancyStuff(x,y,z);
    regptr(s_static_pointer);
}

bool s_init = init(), true; // just run init() before anything else

Foo::Foo() {
  s_static_pointer->doStuff(); // works properly
}
1
ответ дан 24 November 2019 в 07:28
поделиться

Вы можете перегрузить его (если в этом вопросе есть тег "C ++"). Я видел код, в котором для генерации матриц использовалась перегруженная запятая. Или векторы, точно не помню. Разве это не красиво (хотя и немного сбивает с толку):

MyVector foo = 2, 3, 4, 5, 6;

5
ответ дан 24 November 2019 в 07:28
поделиться

Из стандарта C:

Левый операнд оператора запятой оценивается как недействительное выражение; после его оценки есть точка следования. Затем оценивается правый операнд; результат имеет свой тип и значение. (Оператор запятой не дает lvalue.)) Если предпринята попытка изменить результат оператора запятой или получить к нему доступ после следующей точки последовательности, поведение не определено.

Короче говоря, это позволяет вам указать больше чем одно выражение, где C ожидает только одно. Но на практике он в основном используется в циклах for.

Обратите внимание, что:

int a, b, c;

НЕ является оператором запятой, это список деклараторов.

8
ответ дан 24 November 2019 в 07:28
поделиться

Иногда он используется в макросах, таких как макросы отладки, например, такие:

#define malloc(size) (printf("malloc(%d)\n", (int)(size)), malloc((size)))

(Но посмотрите на этот ужасный сбой , ваш покорный слуга, что может случиться, когда вы переусердствуете.)

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

5
ответ дан 24 November 2019 в 07:28
поделиться

The Boost Assignment library is a good example of overloading the comma operator in a useful, readable way. For example:

using namespace boost::assign;

vector<int> v; 
v += 1,2,3,4,5,6,7,8,9;
10
ответ дан 24 November 2019 в 07:28
поделиться

Две убийственные функции оператора запятой в C ++:

a) Чтение из потока до тех пор, пока не встретится определенная строка (помогает сохранить код DRY):

 while (cin >> str, str != "STOP") {
   //process str
 }

b) Написать сложный код в конструкторе инициализаторы:

class X : public A {
  X() : A( (global_function(), global_result) ) {};
};
21
ответ дан 24 November 2019 в 07:28
поделиться

Мне пришлось использовать запятую для отладки блокировок мьютексов, чтобы поместить сообщение до того, как блокировка начнет ждать.

Я не мог оставить сообщение журнала в теле производного конструктора блокировки, поэтому мне пришлось поместить его в аргументы конструктора базового класса, используя: baseclass ((log ("message"), actual_arg)) в списке инициализации. Обратите внимание на дополнительные скобки.

Вот выдержка из классов:

class NamedMutex : public boost::timed_mutex
{
public:
    ...

private:
    std::string name_ ;
};

void log( NamedMutex & ref__ , std::string const& name__ )
{
    LOG( name__ << " waits for " << ref__.name_ );
}

class NamedUniqueLock : public boost::unique_lock< NamedMutex >
{
public:

    NamedUniqueLock::NamedUniqueLock(
        NamedMutex & ref__ ,
        std::string const& name__ ,
        size_t const& nbmilliseconds )
    :
        boost::unique_lock< NamedMutex >( ( log( ref__ , name__ ) , ref__ ) ,
            boost::get_system_time() + boost::posix_time::milliseconds( nbmilliseconds ) ),
            ref_( ref__ ),
            name_( name__ )
    {
    }

  ....

};
10
ответ дан 24 November 2019 в 07:28
поделиться

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

Упрощенный пример:

#define SomeMacro(A) ( DoWork(A), Permute(A) )

Здесь B = SomeMacro (A) «возвращает» результат Permute (A) и присваивает его «B» ".

21
ответ дан 24 November 2019 в 07:28
поделиться

Я думаю, что в целом запятая в C не подходит для использования просто потому, что ее очень-очень легко пропустить - либо кто-то другой пытается прочитать / понять / исправить ваш код, либо вы сами месяц подряд. Вне объявлений переменных и циклов for, конечно, где это идиоматично.

Вы можете использовать его, например, для упаковки нескольких операторов в тернарный оператор (? :), ala:

int x = some_bool ? printf("WTF"), 5 : fprintf(stderr, "No, really, WTF"), 117;

но боже мой, почему ?!? (Я видел, как это использовалось таким образом в реальном коде, но, к сожалению, у меня нет доступа к нему, чтобы показать)

30
ответ дан 24 November 2019 в 07:28
поделиться

Вне цикла for, даже если он может иметь запах кода, единственное место, где я видел хорошее применение оператора запятой, - это как часть удаления :

 delete p, p = 0;

Единственное преимущество перед альтернативой заключается в том, что вы можете случайно скопировать / вставить только половину этой операции, если она выполняется на двух строках.

Мне также это нравится, потому что если вы сделаете это по привычке, вы никогда не забудете нулевое присвоение. (Конечно, почему p не находится внутри какой-то оболочки auto_ptr, smart_ptr, shared_ptr и т. Д., Это другой вопрос.)

5
ответ дан 24 November 2019 в 07:28
поделиться

It's very useful in adding some commentary into ASSERT macros:

ASSERT(("This value must be true.", x));

Since most assert style macros will output the entire text of their argument, this adds an extra bit of useful information into the assertion.

3
ответ дан 24 November 2019 в 07:28
поделиться

Как правило, я избегаю использования оператора запятой, потому что он просто делает код менее читаемым. Почти во всех случаях было бы проще и яснее сделать два утверждения. Например:

foo=bar*2, plugh=hoo+7;

не дает явного преимущества перед:

foo=bar*2;
plugh=hoo+7;

Единственное место, кроме циклов, где я использовал его в конструкциях if / else, например:

if (a==1)
... do something ...
else if (function_with_side_effects_including_setting_b(), b==2)
... do something that relies on the side effects ...

Вы можете поместить функцию перед IF, но если функция принимает долгое время, вы можете захотеть избежать этого, если в этом нет необходимости, и если функция не должна выполняться, если не a! = 1, тогда это не вариант. Альтернатива - вложить IF в дополнительный слой. Я обычно так и делаю, потому что приведенный выше код немного загадочен. Но я делал это время от времени через запятую, потому что вложение тоже загадочно.

было бы проще и яснее сделать два утверждения. Например:

foo=bar*2, plugh=hoo+7;

не дает явного преимущества перед:

foo=bar*2;
plugh=hoo+7;

Единственное место, кроме циклов, где я использовал его в конструкциях if / else, например:

if (a==1)
... do something ...
else if (function_with_side_effects_including_setting_b(), b==2)
... do something that relies on the side effects ...

Вы можете поместить функцию перед IF, но если функция принимает долгое время, вы можете захотеть избежать этого, если в этом нет необходимости, и если функция не должна выполняться, если не a! = 1, тогда это не вариант. Альтернатива - вложить IF в дополнительный слой. Я обычно так и делаю, потому что приведенный выше код немного загадочен. Но я делал это время от времени через запятую, потому что вложение тоже загадочно.

было бы проще и яснее сделать два утверждения. Например:

foo=bar*2, plugh=hoo+7;

не дает явного преимущества перед:

foo=bar*2;
plugh=hoo+7;

Единственное место, кроме циклов, где я использовал его в конструкциях if / else, например:

if (a==1)
... do something ...
else if (function_with_side_effects_including_setting_b(), b==2)
... do something that relies on the side effects ...

Вы можете поместить функцию перед IF, но если функция принимает долгое время, вы можете захотеть избежать этого, если в этом нет необходимости, и если функция не должна выполняться, если не a! = 1, тогда это не вариант. Альтернатива - вложить IF в дополнительный слой. Я обычно так и делаю, потому что приведенный выше код немного загадочен. Но я делал это время от времени через запятую, потому что вложение тоже загадочно.

но если для выполнения функции требуется много времени, вы можете избежать ее выполнения, если в этом нет необходимости, и если функция не должна выполняться, если не a! = 1, то это не вариант. Альтернатива - вложить IF в дополнительный слой. Я обычно так и делаю, потому что приведенный выше код немного загадочен. Но я делал это время от времени через запятую, потому что вложение тоже загадочно.

но если для выполнения функции требуется много времени, вы можете избежать ее выполнения, если в этом нет необходимости, и если функция не должна выполняться, если не a! = 1, то это не вариант. Альтернатива - вложить IF в дополнительный слой. Я обычно так и делаю, потому что приведенный выше код немного загадочен. Но я делал это время от времени через запятую, потому что вложение тоже загадочно.

3
ответ дан 24 November 2019 в 07:28
поделиться