2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему
 
 Ошибка в переключателе switch
Сообщение05.04.2009, 12:46 
Аватара пользователя


10/03/08
82
Код:
//usermenu.cpp
#include "usermenu.h"
#include <iostream>
using namespace std;
void usermenu(polygon& object)
{
   int i_menu;
   do {
      cout << "Enter: 1 - for rectangle, 2 - for centroid, 3 - for rotate, 4 - for move, 5 - for square, 0 - for exit:";
      cin >> i_menu;
      switch(i_menu)
      {
         case 1: object.rectangle();
         break;
         case 2:
         double x_central=0;
         double y_central=0;
         object.centroid(x_central,y_central);
         cout <<"coordinate of centroid: ("<<x_central<<","<<y_central<<")";
         break;
         case 3:
         object.rotate();
         break;
         case 4: object.move();
         break;
         case 5: object.square();
         break;
         case 0: break;
         default: cout <<"Error with enter number!";
      }
      }
   while (i_menu!=0);
   return;
}

На строчке
Код:
case 3:
Ругается:
Код:
[BCC32 Error] usermenu.cpp(21): E2126 Case bypasses initialization of a local variable
В чем может быть проблема?

Добавлено спустя 52 минуты 30 секунд:

Решил проблему :D
Это:
Код:
double x_central=0;
double y_central=0;
до переключателя сделал.

 Профиль  
                  
 
 
Сообщение05.04.2009, 13:36 
Супермодератор
Аватара пользователя


29/07/05
8248
Москва
Другой способ - можно было сделать отдельным блоком (заключить в фигурные скобки).

 Профиль  
                  
 
 
Сообщение05.04.2009, 16:50 


21/03/06
1545
Москва
А мне что-то непонятно, почему компилятор ругнулся...

 Профиль  
                  
 
 
Сообщение05.04.2009, 16:54 
Заслуженный участник


11/05/08
32166
Ещё один способ решения проблемы -- перейти с Си на Паскаль, в котором изначально запрещено объявлять переменные где ни попадя.

(Меня самого когда-то давным-давно, когда пришлось переходить на Паскаль с ПиЭля, эта жёсткость смущала -- но недолго, очень скоро пришёл к выводу, что она абсолютно оправданна.)

 Профиль  
                  
 
 
Сообщение05.04.2009, 18:30 


21/03/06
1545
Москва
Цитата:
Ещё один способ решения проблемы -- перейти с Си на Паскаль, в котором изначально запрещено объявлять переменные где ни попадя.

(Меня самого когда-то давным-давно, когда пришлось переходить на Паскаль с ПиЭля, эта жёсткость смущала -- но недолго, очень скоро пришёл к выводу, что она абсолютно оправданна.)

Во-первых, в Си объявлять переменные где ни попадя нельзя - только в начале блока до исполняемых операторов. В Си++ можно.
Во-вторых, уже общепризнано, что ограничение на объявление переменных это минус, ведущий к менее читабельным и гибким программам.
В третьих перейти с Си на Паскаль - это не способ решения проблемы, а скорее наоборот :).

 Профиль  
                  
 
 
Сообщение05.04.2009, 18:41 
Заслуженный участник


11/05/08
32166
e2e4 в сообщении #202233 писал(а):
Во-вторых, уже общепризнано, что ограничение на объявление переменных это минус, ведущий к менее читабельным и гибким программам.

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

 Профиль  
                  
 
 
Сообщение05.04.2009, 18:49 


24/03/07
321
ну и че, в питоне вон вообще где попало можно функции объявлять. И нормально, народ активно использует.

 Профиль  
                  
 
 
Сообщение05.04.2009, 18:54 
Заслуженный участник


11/05/08
32166
может, и активно, но, но что не приходя при этом в сознание -- то точно

 Профиль  
                  
 
 
Сообщение05.04.2009, 22:35 


21/03/06
1545
Москва
ewert писал(а):
Может быть, и более гибким (хотя большая гибкость сомнительна, мягко говоря), но уж что менее читабельным -- то несомненно.


Бьерн Страуструп. Язык программирования С++ писал(а):
Не описывайте переменную, пока она действительно вам не понадобится, а тогда ее можно
сразу инициализировать, ведь в С++ описание может появляться в любом
месте, где допустим оператор.


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

Так программы не пишутся. Если у Вас один блок занимает тысячи строк, то, согласитесь, объявление переменных в произвольном месте - далеко не то, от чего у программиста будет болеть голова.

Есть серьезное подозрение, что требование объявлять переменные в начале блока идет от желания упростить компилятор, но не жизнь программиста. И потом, нравится объявлять переменные в начале блока - объявляйте, кто Вам это запрещает. Однако я хочу иметь обе возможности, когда пишу программы.

И еще - конструкция подобная этой:

Код:
foo()
{
  ...
  for (int i = 0 ; i < 10; i++)
  {
  }
  ...
}

Проще оптимизируется компилятором, он скорее засунет i в регистр.

 Профиль  
                  
 
 
Сообщение06.04.2009, 12:53 
Заслуженный участник
Аватара пользователя


01/08/06
3131
Уфа
e2e4 в сообщении #202203 писал(а):
А мне что-то непонятно, почему компилятор ругнулся...

Насколько я знаю, любая переменная, согласно стандарту, должна быть объявлена до её использования. Даже если она не используется, а попадает в область видимости. А область видимости переменных x_central, y_central --- с того места, где они объявлены и до конца оператора switch. Т.е. в область видимости этих переменных попадают case 3, case 4 и т.д., но в них можно попасть, не инициализируя эти переменные. Вот компилятор и ругается. Фигурные скобки создают локальную область видимости для этих переменных, и снаружи они становятся невидимыми, поэтому стандарт в этом случае не нарушается.

 Профиль  
                  
 
 
Сообщение06.04.2009, 20:06 


21/03/06
1545
Москва
Цитата:
Насколько я знаю, любая переменная, согласно стандарту, должна быть объявлена до её использования.

Именно так и никак иначе.

Цитата:
Даже если она не используется, а попадает в область видимости. А область видимости переменных x_central, y_central --- с того места, где они объявлены и до конца оператора switch. Т.е. в область видимости этих переменных попадают case 3, case 4 и т.д., но в них можно попасть, не инициализируя эти переменные. Вот компилятор и ругается.

Нуууу... Скорее всего Вы правы. Прблема в синтаксисе оператора switch. Можно посмотреть например это, как пример дурости этого оператора. И тут действительно может возникнуть ситуация использования подобной неинициализированной переменной. Однако, переменная вполне объявлена, и все-таки не должна вызывать недоуменя компилятора. Потом посмотрите, он ругается на то, что для case 3, case 4 переменная не инициализирована:
Цитата:
[BCC32 Error] usermenu.cpp(21): E2126 Case bypasses initialization of a local variable

А это, в принципе, не фатальная ошибка, тянет на warning ИМХО.

Добавлено спустя 5 минут 5 секунд:

Проверил, следующий код:

Код:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
   goto aaa;
   int b;
aaa:
   Label1->Caption = "aaa";
}

Не вызывает ошибки, и такой:
Код:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
   goto aaa;
   int b;
   b = 0;
aaa:
   Label1->Caption = "aaa";
}

Не вызывает. А такой:

Код:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
   goto aaa;
   int b = 0;
aaa:
   Label1->Caption = "aaa";
}
Вызывает ошибку
в Borland Builder 6.0:
Цитата:
[C++ Error] Unit1.cpp(20): E2203 Goto bypasses initialization of a local variable


Однако, непонимаю :). Компилятор ругается, причем фатально, на то, что обходится именно инициализация переменной!

Более того, на такой код тоже ругани нет:
Код:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
   goto aaa;
   int b;
aaa:
   b = 1;
   Label1->Caption = AnsiString(b);
}

(!!!!!!!!)
Т. е., компилятор вполне себе знает переменную b, даже если место ее объявления заведомо "обходится" оператором goto!

Добавлено спустя 4 минуты 29 секунд:

Может быть, кто-нибудь проверит подобные конструкции в не-Borland'овском компиляторе?

 Профиль  
                  
 
 
Сообщение06.04.2009, 23:40 


24/03/07
321
вроде как в gcc
Код:
int b;
b = ...;

и
Код:
int b = ...;

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

Добавлено спустя 6 минут 54 секунды:

да, в gcc результаты такие же как и у вас

Добавлено спустя 1 час 59 минут 1 секунду:

здесь ответ почему http://forums.topcoder.com/?module=Thre ... 95&start=0

 Профиль  
                  
 
 
Сообщение07.04.2009, 16:11 
Супермодератор
Аватара пользователя


29/07/05
8248
Москва
Известно, что компилятор ругается на пропуск инициализации, но спокойно переносит пропуск присваивания.

Добавлено спустя 6 минут 6 секунд:

Объяснение этому может быть такое. Когда программист создает переменную и не инициализирует ее, то это означает, что он делает это сознательно. Это означает, что он будет помнить, что до некоторого момента переменная содержит мусор и пользоваться ей нельзя.
Если же он сразу инициализирует ее, то это означает, что он хочет быть точно уверен, что с самого начала существования переменная содержит строго определенное значение. Программист этого ожидает. Однако переход пропускает этот оператор, переменная при этом должна существовать (так как находится в области видимости), однако содержит мусор. Такого быть не должно, поэтому программист должен разрешить возникающее противоречие тем или иным образом. Компилятор прав, программа при этом принципиально не соответствует задумке программиста и компилироваться не должна.

 Профиль  
                  
 
 
Сообщение07.04.2009, 18:15 


21/03/06
1545
Москва
В общем-то понятно, по ссылке http://forums.topcoder.com/?module=Thread&thre.....mp;start=0 говорится, что компилятор различным образом создает переменную, в зависимости от того, инициализируется она сразу или нет. Видимо, он порождает два разных кода в этих случаях, и, если переменная объявлена с инициализацией, не может разделить эти два вида действия, что приводит к противоречию: либо не создавать переменную (что нельзя, мбо она в области видимости), либо создавать переменную и одновременно ее инициализировать, однако второе - уже исполнимый код, который не должен выполниться из-за goto.

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

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 14 ] 

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group