JohannesD’s answer is correct, but I feel it isn’t entirely clear on an aspect of the problem.
The example he gives declares and initializes the variable i in case 1, and then tries to use it in case 2. His argument is that if the switch went straight to case 2, i would be used without being initialized, and this is why there’s a compilation error. At this point, one could think that there would be no problem if variables declared in a case were never used in other cases. For example:
switch(choice) {
case 1:
int i = 10; // i is never used outside of this case
printf("i = %dn", i);
break;
case 2:
int j = 20; // j is never used outside of this case
printf("j = %dn", j);
break;
}
One could expect this program to compile, since both i and j are used only inside the cases that declare them. Unfortunately, in C++ it doesn’t compile: as Ciro Santilli 包子露宪 六四事件 法轮功 explained, we simply can’t jump to case 2:, because this would skip the declaration with initialization of i, and even though case 2 doesn’t use i at all, this is still forbidden in C++.
Interestingly, with some adjustments (an #ifdef to #include the appropriate header, and a semicolon after the labels, because labels can only be followed by statements, and declarations do not count as statements in C), this program does compile as C:
// Disable warning issued by MSVC about scanf being deprecated
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#ifdef __cplusplus
#include <cstdio>
#else
#include <stdio.h>
#endif
int main() {
int choice;
printf("Please enter 1 or 2: ");
scanf("%d", &choice);
switch(choice) {
case 1:
;
int i = 10; // i is never used outside of this case
printf("i = %dn", i);
break;
case 2:
;
int j = 20; // j is never used outside of this case
printf("j = %dn", j);
break;
}
}
Thanks to an online compiler like http://rextester.com you can quickly try to compile it either as C or C++, using MSVC, GCC or Clang. As C it always works (just remember to set STDIN!), as C++ no compiler accepts it.
|
anubis1768 4 / 4 / 0 Регистрация: 23.02.2013 Сообщений: 151 |
||||
|
1 |
||||
|
02.05.2013, 12:33. Показов 29112. Ответов 1 Метки нет (Все метки)
Здравствуйте. Не один раз встречался с такой ошибкой. Сам не знаю, что она означает, но выправлял я ее с помощью if вместо switch — case. Так вот: здесь уже так у меня не получиться так исправить. Поясните пожалуйста, что эта ошибка означает и как ее исправить.
ЗЫ компилирую с ключом fpermissive
__________________
0 |
|
Croessmah Don’t worry, be happy 17779 / 10543 / 2035 Регистрация: 27.09.2012 Сообщений: 26,513 Записей в блоге: 1 |
||||
|
02.05.2013, 23:55 |
2 |
|||
|
Если объявляете какие-то переменные в блоках case, тогда заключайте содержимое этих блоков в фигурные скобки:
11 |
Содержание
- Часто встречающиеся ошибки стадии компиляции
- Часто встречающиеся ошибки стадии компиляции
- Declaring Variables in Switch Statements
- Why does scope matter?
- Oh right. But how do I fix it?
- 2 thoughts on “Declaring Variables in Switch Statements”
Часто встречающиеся ошибки стадии компиляции
Очень часто начинающие программисты впадают в суеверный ужас, когда видят, что компилятор нашел в тексте программы ошибку, но не понимают, в чем она заключается.
А если помножить этот факт на незнание английского языка («чего там ему не нравится. ») и слабое владение синтаксисом C++ («хм, а может, тут нужна точка с запятой…»), то проблема принимает масштаб катастрофы.
Тот факт, что компилятор в силу своих ограниченных возможностей изо всех сил старается объяснить, что конкретно неверно, не спасает ситуацию. Как быть, если гуглить неохота, а спросить не у кого?
В этом посте на правах копипаста с последующим переводом, дополнениями и исправлениями приведу описание наиболее распространенных сообщений об ошибках и предупреждений компилятора. Неприятность кроется в том факте, что разные компиляторы ругаются на одинаковые ошибки по-разному, а некоторые даже не замечают то, что другие принимают за ошибку. Все зависит от совести разработчиков компилятора, даты его выпуска, и др.
В качестве компилятора возьмем g++, который, в частности, может использоваться в среде Code::Blocks. Версия gcc (куда входит g++) для ОС Windows зовется MinGW. По ходу я буду давать аналоги ошибок из лексикона русскоязычной Microsoft Visual C++.
Итак, частые ошибки:
undeclared identifier
doy.cpp: In function ‘int main()’:
doy.cpp:25: ‘DayOfYear’ undeclared (first use this function)
doy.cpp:25: (Each undeclared identifier is reported only once for each function it appears in.)
doy.cpp:25: parse error before ‘;’ token
2) Смысл
Использован идентификатор DayOfYear , но компилятор не нашел его объявления. Он не знает, что такое DayOfYear .
- Вы забыли включить какой-то заголовочный файл ( #include. )
- Вы где-то ошиблись в написании идентификатора (при объявлении или использовании)
- Вы вообще забыли, что эту переменную надо объявить
Попытавшись скомпилировать это в Microsoft Visual C++, вы увидите:
error C2065: DayOfYear: необъявленный идентификатор
cout undeclared
xyz.cpp: In function ‘int main()’:
xyz.cpp:6: ‘cout’ undeclared (first use this function)
xyz.cpp:6: (Each undeclared identifier is reported only once for each function it appears in.)
2) Смысл
Суперклассика. Без комментариев.
- Вы забыли включить
- Вы забыли написать using namespace std;
jump to case label
switch.cpp: In function ‘int main()’:
switch.cpp:14: jump to case label
switch.cpp:11: crosses initialization of ‘int y’
2) Смысл
Смысл туманен
3) Когда бывает
Вы попытались объявить и инициализировать переменную (объект, указатель и т.п.) в метке case оператора выбора switch. Правилами C++ это запрещено.
В Microsoft Visual C++ эта ошибка зовется
error C2360: пропуск инициализации ‘y’ из-за метки ‘case’
Выход: заключите операторы этого case’а в фигурные скобки <>.
multi-line string / unterminated string
using namespace std;
вызовет бурную реакцию компилятора:
string.cpp:7:12: warning: multi-line string literals are deprecated
string.cpp: In function ‘int main()’:
string.cpp:7: ‘so’ undeclared (first use this function)
string.cpp:7: (Each undeclared identifier is reported only once for each function it appears in.)
string.cpp:7: parse error before ‘Mary’
string.cpp:8:28: warning: multi-line string literals are deprecated
string.cpp:8:28: missing terminating » character
string.cpp:7:12: possible start of unterminated string literal
2) Смысл
Компилятор думает, что мы хотим создать строковую константу с содержащимся в ней переносом строки, что-то типа
что не поддерживается языком. Также делается предположение о том, что мы, возможно, забыли поставить кавычки в конце первой строки. Собственно, так оно и есть.
3) Когда бывает
Когда не соблюдается правильное количество и положение кавычек в строковых литералах. Надо быть внимательнее.
Microsoft Visual C++ со свойственной ему детской непосредственностью, отметит, что нельзя делать переносы в строках и возмутится, где точка с запятой:
error C2001: newline в константе
error C2146: синтаксическая ошибка: отсутствие «;» перед идентификатором «cout»
comparison between signed and unsigned integer expressions
xyz.cpp: In function ‘int main()’:
xyz.cpp:54: warning: comparison between signed and unsigned integer expressions
2) Смысл
Это — предупреждение компилятора, которое говорит о том, что мы пытаемся сравнить (==, и т.д.) целочисленное выражение (может принимать положительные, отрицательные значения и 0) и беззнаковое целочисленное выражение (может быть только положительным, либо 0).
3) Когда бывает
Собственно, тогда и бывает. Напомню, что тип int по умолчанию знаковый, а некоторые функции (например, vector::size() ) возвращают unsigned int .
К примеру, следующий на первый взгляд безобидный код вызовет описываемое предупреждение:
Следует помнить, что в памяти знаковые и беззнаковые типы имеют разные внутренние представления, поэтому надо быть чертовски осторожными с указателями.
В Microsoft Visual C++ предупреждение выглядит так:
suggest parentheses around assignment used as truth value
xyz.cpp: In function `int main()’:
xyz.cpp:54: warning: suggest parentheses around assignment used as truth value
2) Смысл
Тоже классика. Компилятор предполагает (и в 99% случаев прав), что вы по ошибке включили в скобки в качестве условия для if/while/for вместо условного выражения выражение присваивания.
3) Когда бывает
Чаще всего — в if ‘ах, когда вместо «==» используется «=»
if (length = maxLength)
if (length == maxLength)
Заминка в том, что это не ошибка, т.к. в скомпилированной программе (если мы проигнорируем предупреждение) выражение присваивания (которое возвращает значение правого аргумента) во всех случаях, кроме тех, когда оно вернет 0 , будет преобразовано к true .
Источник
Часто встречающиеся ошибки стадии компиляции
Очень часто начинающие программисты впадают в суеверный ужас, когда видят, что компилятор нашел в тексте программы ошибку, но не понимают, в чем она заключается.
А если помножить этот факт на незнание английского языка («чего там ему не нравится. ») и слабое владение синтаксисом C++ («хм, а может, тут нужна точка с запятой…»), то проблема принимает масштаб катастрофы.
Тот факт, что компилятор в силу своих ограниченных возможностей изо всех сил старается объяснить, что конкретно неверно, не спасает ситуацию. Как быть, если гуглить неохота, а спросить не у кого?
В этом посте на правах копипаста с последующим переводом, дополнениями и исправлениями приведу описание наиболее распространенных сообщений об ошибках и предупреждений компилятора. Неприятность кроется в том факте, что разные компиляторы ругаются на одинаковые ошибки по-разному, а некоторые даже не замечают то, что другие принимают за ошибку. Все зависит от совести разработчиков компилятора, даты его выпуска, и др.
В качестве компилятора возьмем g++, который, в частности, может использоваться в среде Code::Blocks. Версия gcc (куда входит g++) для ОС Windows зовется MinGW. По ходу я буду давать аналоги ошибок из лексикона русскоязычной Microsoft Visual C++.
Итак, частые ошибки:
undeclared identifier
doy.cpp: In function ‘int main()’:
doy.cpp:25: ‘DayOfYear’ undeclared (first use this function)
doy.cpp:25: (Each undeclared identifier is reported only once for each function it appears in.)
doy.cpp:25: parse error before ‘;’ token
2) Смысл
Использован идентификатор DayOfYear , но компилятор не нашел его объявления. Он не знает, что такое DayOfYear .
- Вы забыли включить какой-то заголовочный файл ( #include. )
- Вы где-то ошиблись в написании идентификатора (при объявлении или использовании)
- Вы вообще забыли, что эту переменную надо объявить
Попытавшись скомпилировать это в Microsoft Visual C++, вы увидите:
error C2065: DayOfYear: необъявленный идентификатор
cout undeclared
xyz.cpp: In function ‘int main()’:
xyz.cpp:6: ‘cout’ undeclared (first use this function)
xyz.cpp:6: (Each undeclared identifier is reported only once for each function it appears in.)
2) Смысл
Суперклассика. Без комментариев.
- Вы забыли включить
- Вы забыли написать using namespace std;
jump to case label
switch.cpp: In function ‘int main()’:
switch.cpp:14: jump to case label
switch.cpp:11: crosses initialization of ‘int y’
2) Смысл
Смысл туманен
3) Когда бывает
Вы попытались объявить и инициализировать переменную (объект, указатель и т.п.) в метке case оператора выбора switch. Правилами C++ это запрещено.
В Microsoft Visual C++ эта ошибка зовется
error C2360: пропуск инициализации ‘y’ из-за метки ‘case’
Выход: заключите операторы этого case’а в фигурные скобки <>.
multi-line string / unterminated string
using namespace std;
вызовет бурную реакцию компилятора:
string.cpp:7:12: warning: multi-line string literals are deprecated
string.cpp: In function ‘int main()’:
string.cpp:7: ‘so’ undeclared (first use this function)
string.cpp:7: (Each undeclared identifier is reported only once for each function it appears in.)
string.cpp:7: parse error before ‘Mary’
string.cpp:8:28: warning: multi-line string literals are deprecated
string.cpp:8:28: missing terminating » character
string.cpp:7:12: possible start of unterminated string literal
2) Смысл
Компилятор думает, что мы хотим создать строковую константу с содержащимся в ней переносом строки, что-то типа
что не поддерживается языком. Также делается предположение о том, что мы, возможно, забыли поставить кавычки в конце первой строки. Собственно, так оно и есть.
3) Когда бывает
Когда не соблюдается правильное количество и положение кавычек в строковых литералах. Надо быть внимательнее.
Microsoft Visual C++ со свойственной ему детской непосредственностью, отметит, что нельзя делать переносы в строках и возмутится, где точка с запятой:
error C2001: newline в константе
error C2146: синтаксическая ошибка: отсутствие «;» перед идентификатором «cout»
comparison between signed and unsigned integer expressions
xyz.cpp: In function ‘int main()’:
xyz.cpp:54: warning: comparison between signed and unsigned integer expressions
2) Смысл
Это — предупреждение компилятора, которое говорит о том, что мы пытаемся сравнить (==, и т.д.) целочисленное выражение (может принимать положительные, отрицательные значения и 0) и беззнаковое целочисленное выражение (может быть только положительным, либо 0).
3) Когда бывает
Собственно, тогда и бывает. Напомню, что тип int по умолчанию знаковый, а некоторые функции (например, vector::size() ) возвращают unsigned int .
К примеру, следующий на первый взгляд безобидный код вызовет описываемое предупреждение:
Следует помнить, что в памяти знаковые и беззнаковые типы имеют разные внутренние представления, поэтому надо быть чертовски осторожными с указателями.
В Microsoft Visual C++ предупреждение выглядит так:
suggest parentheses around assignment used as truth value
xyz.cpp: In function `int main()’:
xyz.cpp:54: warning: suggest parentheses around assignment used as truth value
2) Смысл
Тоже классика. Компилятор предполагает (и в 99% случаев прав), что вы по ошибке включили в скобки в качестве условия для if/while/for вместо условного выражения выражение присваивания.
3) Когда бывает
Чаще всего — в if ‘ах, когда вместо «==» используется «=»
if (length = maxLength)
if (length == maxLength)
Заминка в том, что это не ошибка, т.к. в скомпилированной программе (если мы проигнорируем предупреждение) выражение присваивания (которое возвращает значение правого аргумента) во всех случаях, кроме тех, когда оно вернет 0 , будет преобразовано к true .
Источник
Declaring Variables in Switch Statements
There you are, happily programming away, when suddenly you get a compile error:
“Huh?” You say, peering at the computer screen. Your code looks fine, so what does it mean?
Look closely at your switch statement. A switch statement contains case labels, which provide options to do different things after checking the value of a variable. However, what you may not realise is that the contents of each of these case labels actually exists in the same scope.
Why does scope matter?
If you declare a variable after a case label, you are actually declaring that variable for all subsequent labels without realising it.
This could lead to you trying to declare the same variable twice (if you’re doing similar things for each case), or worse, for you to inadvertently change the value of a variable under another case.
To stop you from doing this, the compiler flags an error and stops compilation.
Oh right. But how do I fix it?
You can still declare variables in switch statements, you just have to put curly brackets around the code after the case label.
Compare the two examples below. The first one generates an error. The second lets you compile and move on.
1. This generates a compile error:
2. This compiles successfully:
2 thoughts on “Declaring Variables in Switch Statements”
I ran into the sample thing not too long ago writing a CSV parser for C++. This actually brought up a good point, putting stuff into curly brackets basically gives that code it’s own context and scope. That’s something I’ll have to lock away in the brain…..LOL. It’s weird that the switch group doesn’t active more like an if then else.
Haven’t test this but I wonder if this code is also in the same scope.
if (x == 100)
int jim_age=33;
else
int jim_age=36;
Notice no curly brackets. are they both in the same scope?
Ah, C++ – just when you think you’ve figured it all out, it throws an anomaly at you!
They are in their own, separate scope, weirdly enough. A single line after an if or else is a conditional statement, and will only be executed if the condition is met. This means that is has its own scope, despite the lack of brackets.
Conversely, the following is also totally legitimate:
No statement at all, just curly brackets. Mad, eh!
Источник