2014 dxdy logo

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

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




 
 Ошибка в переключателе switch
Сообщение05.04.2009, 12:46 
Аватара пользователя
Код:
//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 
Аватара пользователя
Другой способ - можно было сделать отдельным блоком (заключить в фигурные скобки).

 
 
 
 
Сообщение05.04.2009, 16:50 
А мне что-то непонятно, почему компилятор ругнулся...

 
 
 
 
Сообщение05.04.2009, 16:54 
Ещё один способ решения проблемы -- перейти с Си на Паскаль, в котором изначально запрещено объявлять переменные где ни попадя.

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

 
 
 
 
Сообщение05.04.2009, 18:30 
Цитата:
Ещё один способ решения проблемы -- перейти с Си на Паскаль, в котором изначально запрещено объявлять переменные где ни попадя.

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

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

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

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

 
 
 
 
Сообщение05.04.2009, 18:49 
ну и че, в питоне вон вообще где попало можно функции объявлять. И нормально, народ активно использует.

 
 
 
 
Сообщение05.04.2009, 18:54 
может, и активно, но, но что не приходя при этом в сознание -- то точно

 
 
 
 
Сообщение05.04.2009, 22:35 
ewert писал(а):
Может быть, и более гибким (хотя большая гибкость сомнительна, мягко говоря), но уж что менее читабельным -- то несомненно.


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


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

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

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

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

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

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

 
 
 
 
Сообщение06.04.2009, 12:53 
Аватара пользователя
e2e4 в сообщении #202203 писал(а):
А мне что-то непонятно, почему компилятор ругнулся...

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

 
 
 
 
Сообщение06.04.2009, 20:06 
Цитата:
Насколько я знаю, любая переменная, согласно стандарту, должна быть объявлена до её использования.

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

Цитата:
Даже если она не используется, а попадает в область видимости. А область видимости переменных 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 
вроде как в 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 
Аватара пользователя
Известно, что компилятор ругается на пропуск инициализации, но спокойно переносит пропуск присваивания.

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

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

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

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

 
 
 [ Сообщений: 14 ] 


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group