LINUX.ORG.RU

C++, switch, case ... что-то я туплю

 ,


0

3

Редко пользуюсь оператором switch, хотя думал, что знаю как он работает. Обычно я обязательно пользуюсь break, и switch тогда работает ожидаемо. Но вот я сделал примитивный пример, в котором не могу понять что происходит.

#include <iostream>

using namespace std;

int main (int argc, char *argv[]) 
{
    int i=0;

    switch (i)
    {
    	case 0  : { std::cout << "0"; }
        case 1  : { std::cout << "1"; }
      	default : { std::cout << "D"; }
    }

    return 0;
}


Что выведет этот пример?

Вначале я думал что «0».

Потом не смог найти внятного описания default - выполняется ли это условие только если не подошло ничего из остального, или просто выполняется если до него дошло дело. Я склонился к тому, что default выполняется просто если до него дошло дело (небыло никаких break). Поэтому результат должен быть «0D».

На деле на gcc результат будет таким: «01D».

Два вопроса в связи с этим:

- С какого перепугу в результате затесалось 1?
- Как же все-таки должно срабатывать default?

★★★★★

Последнее исправление: Xintrea (всего исправлений: 2)
Ответ на: комментарий от i-rinat

И точно помню, что когда его увидел, не понял, почему у этого подхода есть своё имя. Потому что там всё было вполне себе очевидно.

Если ты увидев код с goto на метку в середине for сразу понял, как он работает, то ты либо к тому времени много раз писал конечные автоматы на goto (или другой код), либо у тебя врожденное знание C/C++. Хорошо, наверное, быть тобой.

anonymous
()
Ответ на: комментарий от anonymous

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

Бхахаха. Ты эта, аккуратнее. Щас тебе объяснят что только так язык и познается. А та тупая скатина, кто этого не делает, не имеет права пользоваться языком!

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Я так понимаю, что все тут отметившиеся эксперты разбираются во всех нюансах C/C++

Если поведение case в C-шном switch-е без break — это нюанс, то тут вряд ли есть предмет для дальнейшего разговора. Т.к. вообще-то это одна из основополагающих вещей, такая же, например, как разница между статической и автоматической памятью. И описывается поведение case, полагаю, во всех нормальных учебниках по C и C++.

Если ТС-а толком не знает языка, которым он пользуется, то это не проблема тех, кто ему на это незнание мягко или не очень мягко намекает.

Как зайдешь на LOR, так сразу понимаешь ничтожность своего существования.

Многие знания анонимных LOR-овских экспертов вообще не поддаются исчислению.

eao197 ★★★★★
()
Ответ на: комментарий от Dudraug

никогда не было проблем с чтением провалов в case в си

Ага, когда нужен провал и он есть, проблем нет. Зато когда нужен break а его нет - далеко не всегда заметишь глазами.

anonymous
()
Ответ на: комментарий от anonymous

в теме как-то вскользь не обсудили нужность фигурных скобок после case

Что именно? Нужности-то нет

Меня скорее забавляет что после switch синтаксически блок необязателен, а фактически необходим. Фтопку такие синтаксисы.

anonymous
()
Ответ на: комментарий от Xintrea

исполнение идет от первого сматченного условия

это не условия, это метки, переход на соответствующую метку по значению в switch, там обычно и бывает таблица переходов, но не последовательные условия if (); else if(); else ;
Оператор предназначен экономить время для вот таких длинных гирлянд с условиями (обеспечить одинаковое время выполнения блока как для 1-го, так и для последнего варианта, что не обеспечивает гирлянда if;else).

bormant ★★★★★
()
Ответ на: комментарий от Xintrea

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

Бхахаха. Ты эта, аккуратнее. Щас тебе объяснят что только так язык и познается. А та тупая скатина, кто этого не делает, не имеет права пользоваться языком!

Ну, а чо. goto делает переход на метку, поэтому без goto переходы делать нельзя. Логика!

anonymous
()
Ответ на: комментарий от anonymous

Меня скорее забавляет что после switch синтаксически блок необязателен, а фактически необходим. Фтопку такие синтаксисы.

А меня удивляет, зачем в операторе выбора сделали синтаксис с двоеточием и искомым выражением без скобок. Пока что я себе сказал, что это наследие «выбираемого» goto, но синтаксис коробит конкретно.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от eao197

Если поведение case в C-шном switch-е без break — это нюанс

Конкретно то, что описал ТС - это нюанс (хотя бы потому, что на практике такой код почти никогда не нужен). То, что в C# иное поведение - подтверждает, что это нюанс. Впрочем, лично я, когда читал книжку по C хорошо его запомнил, видимо, потому, что там именно такое поведение особо описывалось, т.к. чревато ошибками.

anonymous
()
Ответ на: комментарий от EXL

Что здесь можно обсуждать на 100+ постов?

Прочитай - узнаешь. Вкратце, 2/3 первой страницы - разговор по теме, дальше пустой треп и разговор на связанные и несвязанные темы. Это ж ЛОР.

anonymous
()
Ответ на: комментарий от Xintrea

зачем в операторе выбора сделали синтаксис с двоеточием и искомым выражением

Это синтаксис меток. Вычисляется метка, куда нужно перейти, и выполняется переход.

bormant ★★★★★
()
Ответ на: комментарий от Dudraug

Но вроде такое допустимо

Насколько я понял, нет. Зато у них есть goto case - даже мощнее чем fallthrough, хотя в таких случаях и многословнее.

anonymous
()
Ответ на: комментарий от anonymous

То, что в C# иное поведение

Скорее такое же, они же специально на сишников ориентировались. Там просто обязателен break или другой переход.

anonymous
()

на волне треда спрошу про позабытую мной какую-то аццкую идиому из if()/case(), кто помнит её? Там была какая-то очень странная смесь switch/case/if или while, точно не помню.

former_anonymous ★★★
()
Ответ на: комментарий от former_anonymous

на волне треда спрошу про позабытую мной какую-то аццкую идиому из if()/case(), кто помнит её? Там была какая-то очень странная смесь switch/case/if или while, точно не помню.

Duff's device. 1/3 треда про него.

anonymous
()
Ответ на: комментарий от EXL

Что здесь можно обсуждать на 100+ постов?

Материал, из которого делать навес для стоянки велосипедов.

i-rinat ★★★★★
()
Ответ на: комментарий от anonymous

Чёт я не понял, а как тогда в тех языках обрабатывают широко распространенный случай, когда case 1, case 2 и case 3 нужно обработать одинаково?

В некоторых так

...
case (1, 2, 7, 10:17, 23)
...
grem ★★★★★
()
Ответ на: комментарий от Xintrea

А меня удивляет, зачем в операторе выбора сделали синтаксис с двоеточием и искомым выражением без скобок. Пока что я себе сказал, что это наследие «выбираемого» goto, но синтаксис коробит конкретно.

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

anonymous
()
Ответ на: комментарий от anonymous

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

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

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

Уже выше ссылку дали. Никакой преемственности нет. case - это не какая-то конструкция, а просто метка.

int main() {
  extern int n;
  switch(n) {
    case 20: return 1;
    case(10): return 2;//так?
    default: return 0;
  }
}

Пиши их где хочешь. Только какой в этом смысл - какое отношение имеет case к каким-то инструкциям? У него есть тело? case - это не функция и даже не поход на неё.

anonymous
()
Ответ на: комментарий от Xintrea

по приемственности с остальными конструкциями управления потока команд

Попробуй всё-таки осознать, что case – НЕ конструкция управления потока команд.

// Завидую твоему упорству. Если бы я за столько лет так и не вкурил язык – давно бы бросил, а ты продолжаешь есть кактус познавать мир

Stil ★★★★★
()
Ответ на: комментарий от Xintrea

Вот это меня удивляло, почему исполнение идет невзирая на другие условия.

Низкоуровневость. Можно ускорять программу, если это надо на самом деле, выкидывая break. Break всегда можно поставить и одной инструкцией перехода будет больше, а вот если break вшить, то обратная оптимизация будет трудной и будут 2 инструкции перехода, если тебе надо подряд несколько case выполнять.

peregrine ★★★★★
()
Ответ на: комментарий от Stil

Попробуй всё-таки осознать, что case – НЕ конструкция управления потока команд.

По моему мнению и goto и case - это как раз таки элементы, управляющие потоком команд. Но метку и goto как безусловный или условный переход мы получили из jmp и его условным разновидностям по флагам в ассемблере. Оформление goto на метку отдельным синтаксисом еще как то оправдано. Но case - нет. Точно так же как и if().

Даже циклы на ассемблере тоже оформляютя по меткам, если не делать специальное вычисление адреса. Но для них почему-то сделали синтаксис for().

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

По моему мнению и goto и case - это как раз таки элементы, управляющие потоком команд.

goto – это инструкция перехода, она управляет выполнением. case – это метка, просто именованный кусок кода, она ничем не управляет.

Stil ★★★★★
()
Ответ на: комментарий от Xintrea

Если бы у case небыло параметра, пусть и константного, то да.

«case 0:» это по сути просто метка «case_0:» , нет там никакой магии. В месте управления выполнением (goto или switch) - только там выбирается нужная метка, и это делает компилятор (именно поэтому параметр константный)

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от Dudraug

Он почему то думал, что если не будет брейка, то будет переход в default. Как до такого можно дойти... ну я даже не представляю

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

Rubystar ★★
()
Ответ на: комментарий от Rubystar

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

Даже так...

Dudraug ★★★★★
()
Ответ на: комментарий от Deleted

Это все понятно, но и цикл do-while - это тоже прыжок до метки начала цикла, по своей сути.

Xintrea ★★★★★
() автор топика

Если бы на ЛОРе был раздел «Электротехника», там бы в половине тредов обсуждался цвет изоляции, вкус батареек и эффект, производимый переполюсовкой.

thesis ★★★★★
()
Ответ на: комментарий от Stil

Завидую твоему упорству. Если бы я за столько лет так и не вкурил язык – давно бы бросил, а ты продолжаешь познавать мир

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

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

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

и не боюсь задавать глупые вопросы

Ага, снова и снова, снова и снова.
Лучше бы ты не боялся читать справочную информацию.

thesis ★★★★★
()
Ответ на: комментарий от Xintrea

Мне ее недостаточно

И поэтому ты ее вообще не читаешь? Яснопонятно.

Dudraug ★★★★★
()
Ответ на: комментарий от Xintrea

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

Ты сильно удивишься, если я скажу тебе, что на 99% твоих вопросов уже есть ответы? Достаточно загуглить... И ты найдешь ответы на стековерфлоу, здесь(да-да-! Тут тоже уже многое задвали за столько лет), или, прости господи, мсдне.

Dudraug ★★★★★
()
Ответ на: комментарий от redgremlin

Мне ее недостаточно
Только потому, что ты её даже не открываешь.

Потому что у меня после прочтения еще больше вопросов появляется.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

Потому что у меня после прочтения еще больше вопросов появляется.

Тебе еще на первой странице описали, что свич-кейс в си(и плюсах) - это по сути высокоуровневый гоуту. Док-я описала поведение с примерами, при этом ты уже какую страницу рассказываешь нам о своих фантазиях и представлениях о языке, о том как должно быть. Что тебе еще не понятно по топику?

Dudraug ★★★★★
()
Ответ на: комментарий от Dudraug

Касаемо свитча мне нужны еще подробности, как на низком уровне создается таблица условных переходов на нужную метку, что она из себя представляет, какими принципами руководствовались авторы например gcc при реализации. Я понимаю, что это уже ближе к реализации компилятора. Но ведь у нас и о существовании vtable знать на уровне языка не нужно, а срачи постоянные идут.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

Ты правда куда-то не туда лезешь. Зачем тебе детали реализации? Там бывает таблица переходов, бывает цепочка jmp'ов, что угодно. Не нужно про это знать, как собственно и про устройство vtbl.

anonymous
()
Ответ на: комментарий от Dudraug

Вся портянка не нужна, достаточно:

    switch (i)
  4007ed:	8b 45 fc             	mov    -0x4(%rbp),%eax
  4007f0:	83 f8 01             	cmp    $0x1,%eax
  4007f3:	74 07                	je     4007fc <main+0x25>
  4007f5:	83 f8 02             	cmp    $0x2,%eax
  4007f8:	74 1e                	je     400818 <main+0x41>
  4007fa:	eb 3a                	jmp    400836 <main+0x5f>
    {
        case 1:
          std::cout << "1" << std::endl;
  4007fc:	be 38 09 40 00       	mov    $0x400938,%esi
  400801:	bf 40 0d 60 00       	mov    $0x600d40,%edi
  400806:	e8 b5 fe ff ff       	callq  4006c0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
  40080b:	be e0 06 40 00       	mov    $0x4006e0,%esi
  400810:	48 89 c7             	mov    %rax,%rdi
  400813:	e8 b8 fe ff ff       	callq  4006d0 <_ZNSolsEPFRSoS_E@plt>

        case 2:
          std::cout << "2" << std::endl;
  400818:	be 3a 09 40 00       	mov    $0x40093a,%esi
...


То есть, никакой таблицы переходов, по которой вычисляются адреса даже не создается. Тупо сравнение и jump if equal.

Что-то я не знал о таком сайте, в мемориз однозначно.

Xintrea ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.