Кажется, что
if (x=y) { .... }
вместо
if (x==y) { ... }
является корнем многих зол.
Почему все не компилирует отметьте это как ошибку вместо настраиваемого предупреждения?
Мне интересно узнать, в каких случаях может пригодиться конструкция if (x=y).
@Thomas: Вы правы, меня больше интересует (2). Спасибо, что озвучили это.
Подумайте о расширении вашего компилятора инструментами статического анализа, которые обнаруживают такой "злой" код, например ворсинок.





одна полезная конструкция, например:
char *pBuffer;
if (pBuffer = malloc(100))
{
//continue to work here
}
редактировать:
как уже упоминалось ранее, и за это время я получил несколько голосов против, я могу добавить, что это не особенно хороший стиль, но его можно увидеть достаточно часто, чтобы сказать, что он полезен. Я также видел это с new, но это вызывает больше боли в груди.
Другим примером, менее спорным, может быть:
while (pointer = getNextElement(context))
{
//go for it, use the pointer to the new segment of data
}
что означает, что функция getNextElement() возвращает NULL, когда нет следующего элемента, так что цикл завершается.
Разве нельзя делать это вместо этого? : pBuffer = malloc (100 * sizeof (char)); если (ip == NULL) {printf ("недостаточно памяти \ п"); выход или возврат}
Любой опытный программист знает о явном тесте на 0 / NULL, но вы можете сделать это, чтобы уточнить: if ((p = malloc (100 * ...))! = NULL)
@ Обучение: в наиболее необычном в настоящее время случае, когда вам действительно не хватает памяти, где, по вашему мнению, printf () и последующие вызовы будут получать память для выхода из упомянутого сообщения об ошибке?
люди делают это, поэтому компилятор должен это поддерживать. Даже если это плохая идея.
@llmbus: сейчас дни, когда malloc не работает, обычно нужно запрашивать огромный блок оперативной памяти, я не думаю, что printf нужно где-то рядом с "огромным"
@ S.Lott: есть и похуже, и есть зиггатоны существующего кода, которые так делают.
Потому что это не незаконно (по крайней мере, в C или C++), а иногда и полезно ...
if ( (x = read(blah)) > 0)
{
// now you know how many bits/bytes/whatever were read
// and can use that info. Esp. if you know, say 30 bytes
// are coming but only got 10
}
Большинство компиляторов вызывают настоящую вонь, если вы все равно не ставите скобки вокруг присваивания, что мне нравится.
Но это не тот случай, проверка, если здесь «>», а не «=»? Или я что-то упускаю?
он сначала присваивает x, что аналогично if (x = 0)
Это правильно. Я не понимал, что вы имели в виду только задание, а не просто что-то внутри конструкции. Это была бы интересная грамматика, которая не позволяла бы этого :-)
Многие компиляторы обнаружат это и предупредят вас, но только если вы установите достаточно высокий уровень предупреждения.
Например:
~> gcc -c -Wall foo.c foo.c: In function ‘foo’: foo.c:5: warning: suggest parentheses around assignment used as truth value
Где здесь конструкция if?
Спасибо за ваш комментарий. Я изменил свой пример.
В большинстве случаев компиляторы очень стараются сохранить обратную совместимость.
Изменение их поведения в этом вопросе на выдачу ошибок нарушит существующий законный код, и даже начало выдачи предупреждений об этом вызовет проблемы с автоматическими системами, которые отслеживают код, автоматически компилируя его и проверяя наличие ошибок и предупреждений.
Это зло, с которым мы в значительной степени застряли в банкоматах, но есть способы обойти и уменьшить его опасность.
Пример:
void *ptr = calloc(1, sizeof(array));
if (NULL = ptr) {
// some error
}
Это вызывает ошибку компиляции.
хорошо ... обратная совместимость имеет смысл. Но разве это не сломает код, который, возможно, уже был сломан с самого начала? (Я предполагаю, что вместо == использовалось =). Разве это не хорошо?
В большинстве случаев эти ошибки будут обнаружены. Вы сломаете много кода, в котором нет ошибок.
@Learning - современные компиляторы выдают предупреждение для if (x=y), что помогает
@Learning, Кроме того, вы можете указать компиляторам рассматривать предупреждения как ошибки (что почти всегда хорошо!), Поэтому if (x = y) является ошибкой. Если вы хотите сделать if (x = y), вы можете заключить выражение в другой набор круглых скобок: if ((x = y)). Так вы проясняете ваши намерения.
Дело не в обратной совместимости, а в правильности, в соответствии с определением языка. Компилятор C++, который помечает это как ошибку больше не компилятор C++.
Я думаю (относительно) современные языки, такие как ruby, допускают x = y в условных выражениях, так что это не просто обратная совместимость.
Это зависит от языка. Java помечает это как ошибку, поскольку внутри круглых скобок if могут использоваться только логические выражения (и если две переменные не являются логическими, и в этом случае присваивание также является логическим).
В C это довольно распространенная идиома для тестирования указателей, возвращаемых malloc, или если после вилки мы находимся в родительском или дочернем процессе:
if ( x = (X*) malloc( sizeof(X) ) {
// malloc worked, pointer != 0
if ( pid = fork() ) {
// parent process as pid != 0
Компиляторы C / C++ будут предупреждать с достаточно высоким уровнем предупреждения, если вы попросите об этом, но это не может считаться ошибкой, поскольку язык позволяет это. Если только вы снова не попросите компилятор рассматривать предупреждения как ошибки.
При сравнении с константами некоторые авторы предлагают использовать тест постоянный == Переменная, чтобы компилятор определил, забыл ли пользователь второй знак равенства.
if ( 0 == variable ) {
// the compiler will complaint if you mistakenly
// write =, as you cannot assign to a constant
В любом случае, вы должны попытаться выполнить компиляцию с максимально возможными настройками предупреждений.
+1 за пример вилки. Обычно я храню свой malloc в отдельной строке или с объявлением переменной, что намного удобнее. Затем я проверяю, используя assert или if (x) {...}.
+1 за вилку. Но разве мы не маскируем здесь состояние ошибки, когда fork () выдает ошибку?
@Learning: вы все еще можете проверить, есть ли pid == -1 внутри блока if.
Да, если вы находитесь в части else, вам гарантировано, что вилка сработала, и вы находитесь в дочернем процессе. В части else вам все еще нужно проверить на сбой, но для этого у вас есть переменная pid
Поэтому лучше написать:
0 == CurrentItem
Вместо:
CurrentItem == 0
так что компилятор предупредит вас, если вы наберете = вместо ==.
Не только предупреждает, но и выдает вам ошибку. За исключением случая, когда вы сравниваете значения l (например, * p == * q).
Неужели это такая частая ошибка? Я узнал об этом, когда сам изучил C, и как учитель я иногда предупреждал своих учеников и говорил им, что это обычная ошибка, но я редко встречал ее в реальном коде, даже у новичков. Конечно, не чаще, чем другие ошибки операторов, например, написание «&&» вместо «||».
Так что причина, по которой компиляторы не отмечают это как ошибку (за исключением того, что это совершенно правильный код), возможно, заключается в том, что не является корнем очень многих зол.
В этом есть смысл. Но все же напрашивается вопрос, зачем это позволять? Каков настоящий случай, когда знак = внутри конструкции if имеет смысл?
Я отправил ответ, используя ваши переменные x и y, в котором объясняется, как это работает. И если вы посмотрите на ответ lImbus, то увидите подлинный и очень распространенный случай, когда его имеет смысл использовать и где он часто используется.
Я сделал это. К счастью, любой хороший компилятор выдаст предупреждение.
... и это вполне допустимая и полезная конструкция C.
Простой ответ: операция присваивания, такая как x = y, имеет значение, такое же, как вновь присвоенное значение в x. Вы можете использовать это непосредственно в сравнении, поэтому вместо
x = y; if (x) ...
ты можешь написать
if (x = y) ...
Это меньше кода для написания (и чтения), что иногда хорошо, но в настоящее время большинство людей соглашаются с тем, что его следует написать каким-то другим способом для повышения читабельности. Например так:
if ((x = y) != 0) ...
Вот реальный пример. Предположим, вы хотите выделить некоторую память с помощью malloc, и посмотрите, сработало ли это. Пошагово это можно записать так:
p = malloc(4711); if (p != NULL) printf("Ok!");
Сравнение с NULL является избыточным, поэтому вы можете переписать его следующим образом:
p = malloc(4711); if (p) printf("Ok!");
Но поскольку операция присваивания имеет значение, которое можно использовать, вы можете поместить все присваивание в условие if:
if (p = malloc(4711)) printf("Ok!");
Это делает то же самое, но более кратко.
В вашем примере «if (x = y)» зачем вам нужно if?
Мне нужно «если» во втором фрагменте кода, если я хочу, чтобы он выполнял то же самое, что и мой первый фрагмент кода. Первый фрагмент кода содержал «если», значит, он должен быть и во втором. Но я добавил еще один пример с распределением памяти, чтобы прояснить ситуацию.
Вы спросили, почему это было полезно, но продолжайте сомневаться в примерах, которые приводят люди. Это полезно, потому что оно лаконично.
Да, все примеры, в которых он используется, можно переписать в виде более длинных фрагментов кода.
... и, на мой взгляд, как более четкие фрагменты кода. Ясность важнее (для отладки и поддержки), чем количество байтов, которые занимает источник. См. Соревнования по гольфу. знак равно
Но ясность в глазах смотрящего. Примеры malloc демонстрируют общую идиому.
Кроме того, если код занимает меньше общих строк, то на одном «экране» отображается больше кода, что иногда может помочь в понимании.
Опубликованная "идиома" malloc увеличивает уровень отступа (потому что теперь у вас есть другой блок с действительным указателем alloc'd). В каких случаях было бы предпочтительнее делать что-то только при наличии доступной памяти (и без проблем)? Я никогда не видел, чтобы это использовалось ...
Весь код на «нормальном» пути будет иметь тенденцию всплывать и группироваться под этой идиомой, медленно продвигаясь вправо. В отличие от 4-5 строк обработки ошибок в середине обычного пути, чтобы вы могли забыть о том, что было достигнуто.
Есть несколько тактик, которые помогут это обнаружить ... одна уродливая, другая обычно представляет собой макрос. Это действительно зависит от того, как вы читаете свой разговорный язык (слева направо, справа налево).
Например:
if ((fp = fopen("foo.txt", "r") == NULL))
Против:
if (NULL == (fp = fopen(...)))
Иногда бывает проще прочитать / написать (сначала) то, для чего вы тестируете, что упрощает определение задания по сравнению с тестом. Затем пригласите большинство людей с comp.lang.c, которые страстно ненавидят этот стиль.
Итак, вводим утверждать ():
#include <assert.h>
...
fp = fopen("foo.txt", "r");
assert(fp != NULL);
...
когда вы находитесь в середине или в конце запутанного набора условных выражений, assert () - ваш друг. В этом случае, если FP == NULL, вызывается abort () и передается строка / файл с ошибочным кодом.
Итак, если вы упс:
if (i = foo)
помимо
if (i == foo)
с последующим
assert (i > foo + 1)
... вы быстро заметите такие ошибки.
Надеюсь это поможет :)
Короче говоря, изменение аргументов иногда помогает при отладке. Assert () - ваш долгий друг, и его можно отключить во флагах компилятора в производственных версиях.
Я действительно должен добавить, что код, пронизанный asserts (), должен быть протестирован с флагом компилятора -DNDEBUG перед выпуском ... хотя бы для того, чтобы исключить бесполезные вызовы. Это особенно верно, если в большинстве реализаций вы используете встроенную самодельную функцию assert () вместо предоставленного макроса.
К сожалению, вы злоупотребляете утверждениями. Операторы Assert предназначены для обнаружения вещей, которых не должно происходить, и которые являются ошибками программирования. Использование утверждений для проверки успешности fopen не работает.
Я не использую утверждения для проверки успешности fopen () :) Я проверяю указатель на поток на NULL. Это был просто пример.
Стандартная идиома C для итерации:
list_elem* curr;
while ( (curr = next_item(list)) != null ) {
/* ... */
}
упс, не заметил, что вопрос был просто о «если».
На самом деле такая же концепция, условное присвоение.
Идиома 'if (0 = x)' почти бесполезна, потому что она не помогает, когда обе стороны являются переменными ('if (x = y)') и большую часть (все?) Времени вы должны использовать постоянные переменные а не магические числа.
Две другие причины, по которым я никогда не использую эту идиому. ИМХО, это делает код менее читаемым, и, честно говоря, я считаю, что единственный знак «=» является корнем очень небольшого зла. Если вы тщательно протестируете свой код (что, очевидно, и делаем все мы), такого рода синтаксические ошибки обнаруживаются очень быстро.
Полностью согласен. Я тоже упомянул об этом в своем ответе.
За более чем 20 лет написания кода на C и C++ это укусило меня всего несколько раз и было довольно легко обнаружить (особенно, когда я научился устанавливать максимальный уровень предупреждений).
Это очень часто встречается с конструкциями цикла "низкого уровня" в C / C++, например, с копиями:
void my_strcpy(char *dst, const char *src)
{
while((*dst++ = *src++) != '\0') { // Note the use of extra parentheses, and the explicit compare.
/* DO NOTHING */
}
}
Конечно, для циклов for очень часто используются присваивания:
int i;
for(i = 0; i < 42; ++i) {
printf("%d\n", i);
}
Я действительно считаю, что легче читать назначения, когда они представляют собой за пределами операторов if:
char *newstring = malloc(strlen(src) * sizeof(char));
if (newstring == NULL) {
fprintf(stderr, "Out of memory, d00d! Bailing!\n");
exit(2);
}
// Versus:
if ((newstring = malloc(strlen(src) * sizeof(char))) == NULL) // ew...
Убедитесь, что задание очевидно, thuogh (как в первых двух примерах). Не скрывайте этого.
Что касается случайного использования ... со мной такое случается нечасто. Распространенной защитой является размещение вашей переменной (lvalues) в правой части сравнения, но это не работает с такими вещами, как:
if (*src == *dst)
потому что оба варианта == имеют lvalue!
Что касается компиляторов ... кто может их винить? Писать компиляторы сложно, и вы все равно должны писать идеальные программы для компилятора (помните GIGO?). Некоторые компиляторы (самые известные наверняка) предоставляют встроенную проверку в стиле lint, но это, конечно, не требуется. Некоторые браузеры не проверяют каждый отправленный байт HTML и Javascript, так зачем компиляторам?
Вы можете сделать цикл while еще короче, убрав фигурные скобки и добавив точку с запятой. Я предпочитаю эту формулировку, но некоторых она сбивает с толку.
Попробуйте просмотреть
if ( life_is_good() )
enjoy_yourself();
в виде
if ( tmp = life_is_good() )
enjoy_yourself();
Я собирался зажечь тебя, но потом понял, насколько это полезно. Когда вещи помещены в контекст, это действительно помогает. Однако зачем вам хранить tmp в вашем примере? Возможно, ты сможешь это отрегулировать ...
На практике я этого не делаю, но есть хороший совет:
if ( true == $x )
В случае, если вы не укажете равные значения, присвоение $xtrue, очевидно, вернет ошибку.
Однако часто это ложное чувство безопасности. Что делать, если у вас есть if ($ x == $ y)? Как это изменить, чтобы вызвать ошибку? Единственный реальный ответ - просто научиться не совершать эту ошибку.
Не говоря уже о том, что сравнение с истиной подвержено ошибкам. В большинстве языков, которые не ограничивают истину простым логическим типом, существует несколько истинных значений, и только одно может быть присвоено «истина». Рассмотрим, например, определение true как 1, а $ x - 2.
Я думаю, что разработчики языков C и C++ заметили, что в запрещающий нет реального использования, потому что
Это не сложно. C++ просто говорит, что требуется выражение, неявно конвертируемое в bool. В C есть полезные случаи, подробно описанные в других ответах. В C++ они пошли еще дальше и допустили еще одно:
if (type * t = get_pointer()) {
// ....
}
Что на самом деле ограничивает область действия t только if и его телами.
За 15 лет разработки у меня была эта опечатка только ОДИН РАЗ. Я бы не сказал, что это стоит на первом месте в моем списке вещей, на которые стоит обратить внимание. Я все равно избегаю этой конструкции.
Также обратите внимание, что некоторые компиляторы (тот, который я использую) выдают предупреждение об этом коде. Предупреждения можно рассматривать как ошибки для любого достойного компилятора. Их также можно игнорировать.
Размещение константы слева от сравнения - это защитное программирование. Уверен, что ВЫ никогда не совершите глупую ошибку, забыв этот лишний знак "=", но кто знает о ДРУГОМ парне.
Язык программирования D помечает это как ошибку. Чтобы избежать проблемы с желанием использовать значение позже, он позволяет объявления вроде того, что позволяет C++ с циклами for.
if (int i = some_fn())
{
another_fn(i);
}
Как указано в других ответах, бывают случаи, когда использование присваивания в условии предлагает краткий, но читаемый фрагмент кода, который делает то, что вы хотите. Кроме того, многие современные компиляторы предупредят вас, если увидят назначение там, где они ожидают условие. (Если вы являетесь поклонником подхода к разработке без предупреждений, вы это видели.)
Одна выработанная мною привычка, которая удерживает меня от укуса (по крайней мере, на языках Си-иш), заключается в том, что если одно из двух сравниваемых значений является константой (или иначе не допустимым lvalue), я помещаю его в левой части компаратора: if (5 == x) { whatever(); } Тогда, если я случайно наберу if (5 = x), код не будет компилироваться.
Отчасти это связано с личным стилем и привычками. Я не сторонник чтения if (kConst == x) или if (x == kConst). Я не использую константу слева, потому что исторически я не делаю этой ошибки и пишу код так, как я бы сказал или хотел бы его прочитать. Я рассматриваю это как личное решение как часть личной ответственности за то, чтобы быть самосознательным, улучшающимся инженером. Например, я начал анализировать типы ошибок, которые создавал, и начал перестраивать свои привычки, чтобы они не создавались - аналогично постоянным слева, только с другими вещами.
Тем не менее, предупреждения компилятора исторически довольно дрянные, и хотя эта проблема была хорошо известна в течение многих лет, я не видел ее в производственном компиляторе до конца 80-х годов. Я также обнаружил, что работа над проектами, которые были переносимы, очень помогла мне очистить мой C, так как разные компиляторы и разные вкусы (например, предупреждения) и разные тонкие семантические различия.
Оператор присваивания может использоваться в условных операторах по-разному, и было бы настоящей головной болью постоянно видеть предупреждения о каждом из них. Было бы неплохо, если бы в вашей среде IDE была функция, которая позволила бы вам выделить все места, где использовалось присваивание вместо проверки равенства - или - после того, как вы напишете что-то вроде этого:
if (x = y) {
затем эта строка мигнет пару раз. Достаточно, чтобы вы знали, что сделали что-то не стандартное для точно, но не настолько, чтобы это раздражало.
Я лично считаю это наиболее полезным примером.
Скажем, у вас есть функция read(), которая возвращает количество прочитанных байтов, и вам нужно использовать ее в цикле. Намного проще использовать
while((count = read(foo)) > 0) {
//Do stuff
}
чем пытаться получить задание из заголовка цикла, что приведет к таким вещам, как
while(1) {
count = read(foo);
if (!(count > 0))
break;
//...
}
или же
count = read(foo);
while(count > 0) {
//...
count = read(foo);
}
Первая конструкция кажется неудобной, а вторая неприятным образом повторяет код.
Если, конечно, я не упустил какую-нибудь блестящую идиому для этого ...
Я согласен, что это лучшее использование присваивания в условном выражении, но на самом деле это не относится к операторам if (по запросу OP), а также к циклам while.
Ой, я забыл, что это про if-утверждения. Тогда, конечно, ничего из этого не проблема.
Проблема в том, что вы воспринимаете проблему с ног на голову. Обозначение «if» не предназначено для сравнения двух значений, как в некоторых других языках.
Инструкция C / C++ "if" ожидает любого выражения, которое будет иметь либо логическое значение, либо нулевое / ненулевое значение. Это выражение может включать сравнение двух значений и / или может быть гораздо более сложным.
Например, у вас может быть:
if (i >> 3)
{
std::cout << "i is less than 8" << std::endl
}
Это доказывает, что в C / C++ выражение if не ограничивается == и =. Подойдет все, что угодно, если оно может быть оценено как истинное или ложное (C++) или как ноль, отличное от нуля (C / C++).
Другое допустимое использование C++:
if (MyObject * pObject = dynamic_cast<MyInterface *>(pInterface))
{
pObject->doSomething() ;
}
И это простое использование выражения if (обратите внимание, что это также можно использовать в строке объявления цикла for). Существуют более сложные варианты использования.
After discovering a duplicate of this question at В каком случае, если (a = b) - хорошая идея?, я решил дополнить этот ответ дополнительным бонусом, то есть инъекцией переменной в область видимости, которая возможна в C++, потому что if будет оценивать свое выражение, включая объявление переменной, вместо того, чтобы ограничивать себя сравнением двух операндов, как это сделано на других языках:
Итак, цитирую от себя:
Другой вариант использования - это то, что называется C++ Variable Injection. В Java есть это классное ключевое слово:
synchronized(p)
{
// Now, the Java code is synchronized using p as a mutex
}
В C++ это тоже возможно. Я не имею в виду точный код (ни точную статью DDJ, где я его обнаружил), но этого простого определения должно быть достаточно для демонстрационных целей:
#define synchronized(lock) \
if (auto_lock lock_##__LINE__(lock))
synchronized(p)
{
// Now, the C++ code is synchronized using p as a mutex
}
Таким же образом, смешивая инъекцию с if и для объявления, вы можете объявить примитивный макрос foreach (если вам нужен foreach промышленного уровня, используйте boost).
См. Следующие статьи для менее наивной, более полной и надежной реализации:
Редко. На самом деле, я еще не вспомнил ни одного, а я профессионал уже 8 лет. Я предполагаю, что это произошло, но затем, за 8 лет, я действительно произвел значительное количество ошибок. Просто такого рода ошибок было недостаточно, чтобы я с разочарованием вспомнил о них.
В C у вас будет больше ошибок из-за переполнения буфера, например:
void doSomething(char * p)
{
strcpy(p, "Hello World, how are you \?\n") ;
}
void doSomethingElse()
{
char buffer[16] ;
doSomething(buffer) ;
}
Фактически, Microsoft так сильно обиделась из-за того, что они добавили в Visual C++ 2008 предупреждение об отказе от strcpy !!!
Самая первая «защита» от этой ошибки - это «развернуть» выражение: поскольку вы не можете присвоить значение константе, это:
if (0 = p) // ERROR : It should have been if (0 == p). WON'T COMPILE !
Не компилируется.
Но я считаю это довольно плохим решением, потому что оно пытается скрыть за стилем то, что должно быть общей практикой программирования, а именно: любая переменная, которая не должна изменяться, должна быть постоянной.
Например, вместо:
void doSomething(char * p)
{
if (p == NULL) // POSSIBLE TYPO ERROR
return ;
size_t length = strlen(p) ;
if (length == 0) // POSSIBLE TYPO ERROR
printf("\"%s\" length is %i\n", p, length) ;
else
printf("the string is empty\n") ;
}
Попытка "константировать" как можно больше переменных позволит вам избежать большинства ошибок опечаток, в том числе тех, которые не находятся внутри выражений "если":
void doSomething(const char * const p) // CONST ADDED HERE
{
if (p == NULL) // NO TYPO POSSIBLE
return ;
const size_t length = strlen(p) ; // CONST ADDED HERE
if (length == 0) // NO TYPO POSSIBLE
printf("\"%s\" length is %i\n", p, length) ;
else
printf("the string is empty\n") ;
}
Конечно, это не всегда возможно (так как некоторые переменные необходимо изменить), но я обнаружил, что большинство используемых мной переменных являются константами (я продолжаю инициализировать их один раз, а затем только их читаю).
Обычно я вижу код, использующий нотацию if (0 == p), но без константной нотации.
Для меня это все равно, что иметь мусорное ведро для вторсырья, а другое - для неперерабатываемых, а затем, в конце концов, выбросить их в один контейнер.
Так что не повторяйте привычку к простому стилю, надеясь, что это сделает ваш код намного лучше. Не будет. По возможности используйте языковые конструкции, что означает, в данном случае, использование как записи if (0 == p), если она доступна, так и использования ключевого слова const в максимально возможной степени.
Хуже всего, когда вы начинаете видеть подобные вещи на языках, где использование = в любом случае будет синтаксической ошибкой, таких как C# или Python.
В качестве примечания, я переключился на языки с синтаксисом типа C именно из-за такой "свободной" нотации (точнее, обозначения "for", так что я мог быть несколько предвзятым) ... ^ _ ^
Условное присвоение допустимо для C и C++, и любой компилятор, который не разрешает его, не является настоящим компилятором C или C++. Я надеюсь, что любой современный язык, не предназначенный для явной совместимости с C (как был C++), сочтет это ошибкой.
Бывают случаи, когда это позволяет кратким выражениям, таким как идиоматический while (*dest++ = *src++);, копировать строку на C, но в целом это не очень полезно, и я считаю это ошибкой в языковом дизайне. По моему опыту, эту ошибку легко сделать и трудно обнаружить, если компилятор не выдает предупреждения.
Компилятор не будет отмечать это как ошибку, потому что он действителен для C / C++. Но что вы можете сделать (по крайней мере, с Visual C++), так это поднять уровень предупреждения, чтобы он пометил его как предупреждение, а затем сказал компилятору рассматривать предупреждения как ошибки. В любом случае это хорошая практика, чтобы разработчики не игнорировали предупреждения.
Если вы на самом деле имели в виду = вместо ==, тогда вам нужно сказать об этом более четко. например
if ((x = y) != 0)
Теоретически вы должны уметь это:
if ((x = y))
чтобы отменить предупреждение, но это не всегда работает.
if ((k==1) || (k==2)) is a conditional
if ((k=1) || (k=2) ) is BOTH a conditional AND an assignment statement
Как и большинство языков, C работает от внутреннего к внешнему в порядке приоритета операторов.
Сначала он пытается установить k равным 1, и ему это удается.
Result: k = 1 and Boolean = 'true'
Далее: устанавливает k равным 2 и успешно.
Result: k = 2 and Boolean = 'true'
Далее: он оценивает (истина || истина)
Result: k still = 2, and Boolean = true
Наконец, он разрешает условие: If (true)
Result: k = 2 and the program takes the first branch.
За почти 30 лет программирования я не видел веской причины для использования этой конструкции, хотя, если она существует, вероятно, это связано с необходимостью намеренно запутать ваш код.
Когда у кого-то из наших новых людей возникает проблема, это одна из вещей, которую я ищу, наряду с тем, чтобы не наклеивать терминатор на строку и копировать оператор отладки из одного места в другое и не менять '% i на' % s 'для соответствия новому выгружаемому полю.
Это довольно распространено в нашем магазине, потому что мы постоянно переключаемся между C и Oracle PL / SQL; if (k = 1) ЕСТЬ правильный синтаксис в PL / SQL.
Образец RegEx
RegEx r;
if (((r = new RegEx("\w*)).IsMatch()) {
// ... do something here
}
else if ((r = new RegEx("\d*")).IsMatch()) {
// ... do something here
}
назначить тест ценности
int i = 0;
if ((i = 1) == 1) {
// 1 is equal to i that was assigned to a int value 1
}
else {
// ?
}
Я думаю, что на самом деле это два разных вопроса, и вы должны уточнить, какой из них вы хотите задать: (1) действительно ли эта конструкция что-нибудь означает, и в этом случае что, и (2) если она более опасна, чем полезно, почему это все еще законно.