ページ 1 / 1
aの初期化がcaseラベルによって行われませんでしたとは?
Posted: 2014年8月11日(月) 11:29
by 新宿の翼
switch文の中でswitchを作り、そのswitchの中で
動的な変数を作った場合によく件名のエラーが出ます。
そんなときは、その変数を利用している箇所を{ }で囲んでやると回避できるのですが、
まったくの無印でカッコをつけてやることが奇妙に感じますし、
それでなぜ解決出来たのか理解はしていないのでいつももやもやしています。
どういうことなのか、ぜひご教示よろしくお願いします。
ちなみに、下記がそのエラーが出るパターンです。
コード:
switch( ){
case 0:
int a=0;
switch( ){
case 0:
a=1;
break;
case 1:
b=2;
break;
}
break;
case 1:
break;
}
で、これを下記の様に{}で囲むと解決します。
コード:
switch( ){
case 0:
{ ←追加
int a=0;
switch( ){
case 0:
a=1;
break;
case 1:
b=2;
break;
}
} ←追加
break;
case 1:
break;
}
どういうことでしょう?
Re: aの初期化がcaseラベルによって行われませんでしたとは?
Posted: 2014年8月11日(月) 11:58
by box
switch文の中の、ある特定のcaseにおいて
変数を定義する必要がある、という状況が
よくわかりません。
# 「動的」というのは、本件の場合、どういう意味を持つのでしょうか。
# 別にmalloc()とかで領域を「動的に」確保しているわけでもなさそうですし。
Re: aの初期化がcaseラベルによって行われませんでしたとは?
Posted: 2014年8月11日(月) 12:01
by softya(ソフト屋)
switch文は1つのブロックですので、case単位では変数を生成出来ません。
caseは特殊な動きをするので通るルートによって変数が生成されたりされなかったりするのはC/C++の規格上マズイのです。それを許す言語もあります。
caseってbreak;が無いと下の処理に流れたりしますよね。
あとインデントはきれいに書きましょう。バグのもとです。
box さんが書きました:switch文の中の、ある特定のcaseにおいて
変数を定義する必要がある、という状況が
よくわかりません。
この例はすごく意味無いですけどね。
Re: aの初期化がcaseラベルによって行われませんでしたとは?
Posted: 2014年8月12日(火) 10:43
by 新宿の翼
box さんが書きました:switch文の中の、ある特定のcaseにおいて
変数を定義する必要がある、という状況が
よくわかりません。
# 「動的」というのは、本件の場合、どういう意味を持つのでしょうか。
# 別にmalloc()とかで領域を「動的に」確保しているわけでもなさそうですし。
質問の意図がよくわかりません。
まず動的というのは、簡単に言えばそのスコープ内だけで必要とする変数、でよろしいですよね?
で、千差万別のプログラム処理方法において
そんな状況はプログラム者が考えようと思えば、いくらでもあると思うのですが違いますか?
(煽りでもなんでも無く、そう思うのですが、、)
言葉でその状況を説明するのは難しいんですけど説明してみます。
うまく例えになってるかわかりませんが、
ひとつのobjectクラスを作ったとして、そのobjectは
受け取る値(level_Aとします)によって、更新内容がまったく別なものになるとします。
そしたらこの段階で自分は初期化、更新内をswitch(level_A)とわけて書こうとします。
で、それら各levelの更新の中で、さらに別のlevel値(level_Bとします)によって
なにかが発生する時間(startとします)も個別で設定したいとします。
start値を更新フレーム数が超えたら、それを発生させる、ってやつです。
更新の中で、このstart値は
あくまでフレーム数がそれを過ぎたことを判断するための
マークとしてほしいだけですから、
いちいちクラスのpublicでstart変数を作る気にならないわけで、
if(start>フレーム)の前に、start変数を作り、
そのstartの値はswitch(level_B)によって確保。
その数値を超えるほどフレームがまわったか?を
毎回判定している、といった流れです。
自分は過去に、静的変数(強いてはグローバル変数)で値を扱うのはラクだが
必要ないときでも常にメモリは確保しているので多用は禁物的な話を聞いています。
動的はそのスコープが終われば消されるんで、出来れば動的変数を使うべし、と認識しています。
なので、上記のような利用方法でやってるんですけど
おかしい方法ですかね?
更新の中で、level_Bの値によって分けられるstart値
そのstartの値を超えたら発生するわけですが
(levelBの数値はlevelA)
Re: aの初期化がcaseラベルによって行われませんでしたとは?
Posted: 2014年8月12日(火) 11:05
by 新宿の翼
softya(ソフト屋)さんの回答は
こちらの質問がまったく伝わっていないのかな?と
思ってしまいますが、違いますか?
softya(ソフト屋) さんが書きました:
caseってbreak;が無いと下の処理に流れたりしますよね。
すみません、この発言の意図がわかりません。
自分の記載したcaseのソースでも別にそこの対処は出来てますよね?
break記載してないと処理が流れるのは知ってるんですけど、、、、
先のなにかにかけて話したのでしょうか?それならそれでいいのですが
こちらは読み取れませんでした。
(ちなみに、breakを書かずにわざと次のブロックの処理も行わせる方法も
使う人は使いますから、caseのbreakって必須じゃ無いはずですよ)
softya(ソフト屋) さんが書きました:
caseは特殊な動きをするので通るルートによって変数が生成されたりされなかったり
自分の例で書いたswitch文に対しては、この指摘は当てはまらないと思うんですが?
僕の質問にある例でいうなら、動的変数はcase 0を通る場合にしか要らないわけですから
別のルートを通れば、そりゃ要らないわけです。
別のルートだと生成されくていいんですが、、、そこに上記のあなたのこの指摘は
どうかかるんでしょう?読み取れませんが、、、
softya(ソフト屋) さんが書きました:
あとインデントはきれいに書きましょう。バグのもとです。
これもまったく意味がわかりません。
確かに例で書いたものはインデントがずれていますが、
例で書いたソースは手打ちしたものです。
この掲示板、Tabキーでスペース空きませんよね?
わざわざスペースキーをトントン押して書くしかないわけです。
ソースをコピペで貼り付けたわけではないので。
スペースキーをとんとんと地道に打たなきゃならない時点で、
あくまで例として説明したいものなんですから
てきとーなところで切り上げますって。
それを「インデントは揃えましょう」って言われても、、、、
デートに着ていく服はこれでいいですか?ってその服を着た写メを見せたときに
服だけ見てもらいたいからって寝癖頭で写メ取ったら
「寝癖は直しましょうね」って注意された感じなんですが。
「いやいや、んなことはわかってるって」って答えますよね。
結局、僕の質問に対し、まったく的を射た答えがないですよね?
副管理人という役職をお持ちみたいですが大丈夫ですか?
Re: aの初期化がcaseラベルによって行われませんでしたとは?
Posted: 2014年8月12日(火) 12:08
by Hiragi(GKUTH)
新宿の翼 さんが書きました:softya(ソフト屋)さんの回答は
こちらの質問がまったく伝わっていないのかな?と
思ってしまいますが、違いますか?
softya(ソフト屋) さんが書きました:
caseってbreak;が無いと下の処理に流れたりしますよね。
すみません、この発言の意図がわかりません。
自分の記載したcaseのソースでも別にそこの対処は出来てますよね?
break記載してないと処理が流れるのは知ってるんですけど、、、、
先のなにかにかけて話したのでしょうか?それならそれでいいのですが
こちらは読み取れませんでした。
(ちなみに、breakを書かずにわざと次のブロックの処理も行わせる方法も
使う人は使いますから、caseのbreakって必須じゃ無いはずですよ)
caseは特殊な動きをするということについて一例を上げたのだと思います。
加えてcase の breakは必須ではありませんが、書き忘れによるバグの温床とされているので一部の言語では禁止されていたり或いは警告が出るようになっています。
新宿の翼 さんが書きました:softya(ソフト屋) さんが書きました:
caseは特殊な動きをするので通るルートによって変数が生成されたりされなかったり
自分の例で書いたswitch文に対しては、この指摘は当てはまらないと思うんですが?
僕の質問にある例でいうなら、動的変数はcase 0を通る場合にしか要らないわけですから
別のルートを通れば、そりゃ要らないわけです。
別のルートだと生成されくていいんですが、、、そこに上記のあなたのこの指摘は
どうかかるんでしょう?読み取れませんが、、、
「別ルートだと生成されなくていい」のがマズいのだと思います。
ルートによって生成されるか生成されないかが違うのがC/C++の構造上マズいと言ってるのではないでしょうか?
新宿の翼 さんが書きました:softya(ソフト屋) さんが書きました:
あとインデントはきれいに書きましょう。バグのもとです。
これもまったく意味がわかりません。
確かに例で書いたものはインデントがずれていますが、
例で書いたソースは手打ちしたものです。
この掲示板、Tabキーでスペース空きませんよね?
わざわざスペースキーをトントン押して書くしかないわけです。
ソースをコピペで貼り付けたわけではないので。
スペースキーをとんとんと地道に打たなきゃならない時点で、
あくまで例として説明したいものなんですから
てきとーなところで切り上げますって。
掲示板に直接コードを打ち込んでいるのですか?
そうなのであればテキストエディタで打ち込んでコピペしたほうが圧倒的に良いのではないのでしょうか、
それと他人にコードを見せるときは規模の大きさに関わらずインデントを揃えるのが普通です。
そのほうが相手も読みやすいですし回答しやすいでしょう
質問に関してですが、{}がある場合、int aのスコープは{}の中で完結する(寿命が尽きる)のでもし他のラベルcase 1:などを通過した場合でも問題はありません。
しかし{}がない場合、int aのスコープはswitch文が終わるまであります、この時、もしcase 1:などを通過した場合スコープはあるのに変数は宣言されていないという矛盾が
起きてしまいます。このことが「C/C++の構造上マズい」のでコンパイラはエラーを出すようです。
参照:
http://blogs.konuma.org/blog/2005/11/switch_64b8/
Re: aの初期化がcaseラベルによって行われませんでしたとは?
Posted: 2014年8月12日(火) 13:08
by softya(ソフト屋)
一言で言えば、言語仕様として矛盾しないように言語規格は決まっているので、言語規格に文句を言っても始まらないって事です。
喧嘩を売りたいのであれば他の掲示板へどうぞ。
Re: aの初期化がcaseラベルによって行われませんでしたとは?
Posted: 2014年8月13日(水) 03:19
by かずま
コード:
// a0.cpp
int main()
{
switch (0) {
case 0:
int a = 0;
break;
case 1:
break;
}
}
上記の C++ プログラム a0.cpp を Microsoft の Visual C++ でコンパイルすると
次のようなエラーメッセージが表示されます。
コード:
a0.cpp(8) : error C2360: 'a' の初期化が 'case' ラベルによって行われませんでした。
a0.cpp(6) : 'a' の宣言を確認してください。
エラーが出ないようにするには、次のようないくつかの方法があります。
a1.cpp -- case 0: と break; の間に { } を付ける。
a2.cpp -- a の初期化を宣言時に行わず、代入で行う。
a3.cpp -- case 1: break; を先に書く。
コード:
// a1.cpp
int main()
{
switch (0) {
case 0:
{
int a = 0;
}
break;
case 1:
break;
}
}
コード:
// a2.cpp
int main()
{
switch (0) {
case 0:
int a;
a = 0;
break;
case 1:
break;
}
}
コード:
// a3.cpp
int main()
{
switch (0) {
case 1:
break;
case 0:
int a = 0;
break;
}
}
以下、説明です。
a0.cpp は、8行目の case 1: のところがエラーです。
自動変数 a の有効範囲は、caseラベルとは無関係に、
6行目の int a = 0; から 10行目の } までです。
自動変数 a の初期化は、6行目を通らないと実行されません。
ということは、case 1: のラベルに飛んできた場合、
a は存在するのに、初期化されていないという状況になり、
C++ ではこれをエラーとして扱うことになっています。
a1.cpp は、case 1: のラベルのところでは a は存在しないので
エラーになりません。
a2.cpp は、int a; の宣言により、case 1: のところで a は存在していて、
宣言通り未初期化なのでエラーになりません。
a3.cpp は、case 1: のラベルのところでは、a は存在していないので
エラーになりません。
なお、C++ では、int a; や int a = 0; は宣言文という文なので、
ラベルを付けることができますが、
C では、int a; や int a = 0; は、宣言ではあるが、文ではないので
ラベルを付けることができず、a1.cpp 以外は全部エラーになります。
ただし、異なるエラーメッセージです。
コード:
error C2143: 構文エラー : ';' が '型' の前にありません。
Re: aの初期化がcaseラベルによって行われませんでしたとは?
Posted: 2014年8月16日(土) 17:51
by かずま
box さんが書きました:switch文の中の、ある特定のcaseにおいて
変数を定義する必要がある、という状況が
よくわかりません。
コード:
switch (op) {
case '+':
push(pop() + pop());
break;
case '-':
double y = pop();
push(pop() - y);
break;
}
push の引数に pop() が 2つあると、
どちらが先に実行されるか決まっていません。
'+' の場合、x + y == y + x なので、どちらでも構わないのですが、
'-' の場合、x - y と y - x は等しいとは限らないので、
pop() の評価順序を制御するため、上記のような局所変数が必要になります。
box さんが書きました:
# 「動的」というのは、本件の場合、どういう意味を持つのでしょうか。
# 別にmalloc()とかで領域を「動的に」確保しているわけでもなさそうですし。
オブジェクト(変数) の記憶域の寿命に、
静的(static)、自動(automatic)、動的(dynamic) の
3 つがあることをすべての人が知っているわけではありません。
さらに、最新の C++ では、その 3つに加えて、
スレッド(thread) というのも追加されています。
プログラムには int a=0; とあり、a は自動変数なのですが、
質問者がその用語を知らなくて、「静的ではない」という意味で
「動的」と言ってしまったのだろうと察してあげてください。
Re: aの初期化がcaseラベルによって行われませんでしたとは?
Posted: 2014年8月16日(土) 17:56
by かずま
softya(ソフト屋) さんが書きました:switch文は1つのブロックですので、case単位では変数を生成出来ません。
caseは特殊な動きをするので通るルートによって変数が生成されたりされなかったりするのはC/C++の規格上マズイのです。それを許す言語もあります。
caseってbreak;が無いと下の処理に流れたりしますよね。
swich文は、「switch (式) 文」という構文で、
それ自身は「ブロック」ではありません。
コード:
switch (argc)
case 1: printf("argc == 1\n");
は
コード:
if (argc == 1)
printf("argc == 1\n");
と同じです。
通常は、「式の値」に応じて、
複数の「caseラベルを持つ文」のどれかに分岐するものなので、
switch文の中の「文」は、複合文すなわちブロックになります。
「switch (式) { ラベル付きのものがある文の並び } 」
それから、変数の生成にルートは関係ありません。
コード:
switch (argc) {
int a;
case 1:
a = 1; printf("case 1: a=%d\n", a); break;
case 2:
a = 2; printf("case 2: a=%d\n", a); break;
}
このコードはエラーになりません。
argc の値により、case 1 に飛ぼうが、case2 に飛ぼうが
変数 a は生成されていて使用できます。
ブロックに飛び込みさえすれば、ルートは関係ありません。
ルートが問題になるのは、変数の「初期化」です。
質問のタイトルが「aの初期化がcaseラベルによって行われませんでしたとは?」
ですから、なぜこのエラーが出るのかについて回答しないと、
質問者から不満が出るのは当然だと思います。
Re: aの初期化がcaseラベルによって行われませんでしたとは?
Posted: 2014年8月16日(土) 18:00
by かずま
Hiragi(GKUTH) さんが書きました:
質問に関してですが、{}がある場合、int aのスコープは{}の中で完結する(寿命が尽きる)のでもし他のラベルcase 1:などを通過した場合でも問題はありません。
「名前(識別子)のスコープ(有効範囲)」と
「オブジェクト(変数)の寿命」とは別の概念です。
コード:
{
int a = 3;
{
int a = 5;
printf("a = %d\n", a);
}
printf("a = %d\n", a);
}
値が 3 の a の寿命は、2~8行目ですが、
スコープは、2~3、7~8行目です。
値が 5 の a は、寿命とスコープが一致します。
Hiragi(GKUTH) さんが書きました:
しかし{}がない場合、int aのスコープはswitch文が終わるまであります、この時、もしcase 1:などを通過した場合スコープはあるのに変数は宣言されていないという矛盾が
起きてしまいます。このことが「C/C++の構造上マズい」のでコンパイラはエラーを出すようです。
case 1: を通過した場合、変数は宣言されており、スコープがあります。
初期化がされないことを言わないと、
エラーメッセージの説明をしたことになりません。
また、このエラーメッセージは C++ だけで出ますから、
「C/C++の構造上マズい」のようにまとめて言ってしまうのは問題だと思います。
Re: aの初期化がcaseラベルによって行われませんでしたとは?
Posted: 2014年8月16日(土) 18:59
by softya(ソフト屋)
かずまさん。掲示板が荒れそうになっているトピックに更に火種を投入しないでいただけますか。
話をややこしくしないで下さい。
ご不満等あれば別トピックでお願いします。mixc++に登録いただければメール等でも説明いたします。
Re: aの初期化がcaseラベルによって行われませんでしたとは?
Posted: 2014年8月20日(水) 18:25
by ISLe()
かずまさんの指摘に何の問題があるのでしょう。
回答者にはことさら理解を求めるのに、かずまさんの指摘にあるような基本を理解していないと思われる回答が横行することは問題ではないのでしょうか。
また個人に対して警告等を発することによる他の利用者へ影響(個人攻撃の誘発など)は考慮されているのでしょうか。
はっきり言って、回答者が曖昧な回答をするせいでたくさんのトピックが無用の長物になっていると感じることが多くなってます。
質問者みずから荒らす行為はとうぜん問題ですが、回答者が荒れても良い雰囲気を作っているとも思います。
過去ログとして価値のあるトピックにしたいのならむしろかずまさんの指摘は良いものだと思います。
問題のある質問者を追い出すためにトピックを利用することが運営として適当だと判断されているのでしょうか。
そのために他の掲示板利用者の表現の自由が奪われるということに対して問題だとは思われないのでしょうか。
Re: aの初期化がcaseラベルによって行われませんでしたとは?
Posted: 2014年8月20日(水) 18:51
by Hiragi(GKUTH)
>>かずまさん >>ISLeさん
すいません。私自身あまり変数について詳しくない(寿命、スコープの違いなど)まま、回答してしまいました。勘違いを指摘してくださってありがとうございます。
ネットでの情報を自分に都合よく解釈してしまっていたようです。回答者という立場上、質問に対しての回答には自身を持てるモノを持つべきだと思いました。
私自身まだプログラミングについてそれほど経験が無い、という中で感情的な部分だけで書き込みをしてしまったことに対して情けないと思います。
この掲示板の有り方については私が言うことでは無いでしょうが、回答者側が問題であるという考え方に気づいていませんでした。
この掲示板が出来てからそれなりの時間が立ちますが、最近になってこのような(質問自体ではなく質問者や回答者に対しての課題)ことが多くなってきたように感じます。
なぜこのようになったのかはわかりませんが...(回答者の意識が変わり始めた?)
Re: aの初期化がcaseラベルによって行われませんでしたとは?
Posted: 2014年8月20日(水) 21:08
by box
ISLe() さんが書きました:
回答者が曖昧な回答をする
このこと自体は問題ないと考えます。
回答する側にあいまいでない(厳密な?)回答を求めるのは、酷というものです。
回答しようとする人すべてが
Cの規格や用語や文法などについて
疑義を挟む余地のない知識を持っている
「とは限らない」のであります。
このトピックで問題があるとすれば、運営者から
softya(ソフト屋) さんが書きました:
喧嘩を売りたいのであれば他の掲示板へどうぞ。
とか
softya(ソフト屋) さんが書きました:掲示板が荒れそうになっているトピックに更に火種を投入しないでいただけますか。
話をややこしくしないで下さい。
とかいう投稿があった点だと思います。
# この投稿も「荒らし」と判定されるんだろうか…。
Re: aの初期化がcaseラベルによって行われませんでしたとは?
Posted: 2014年8月21日(木) 00:37
by もふらん
ちょっとこのスレを見ていたのですが
box さんが書きました:
このトピックで問題があるとすれば、運営者から
softya(ソフト屋) さんが書きました:
喧嘩を売りたいのであれば他の掲示板へどうぞ。
とか
softya(ソフト屋) さんが書きました:掲示板が荒れそうになっているトピックに更に火種を投入しないでいただけますか。
話をややこしくしないで下さい。
とかいう投稿があった点だと思います。
# この投稿も「荒らし」と判定されるんだろうか…。
確かにかずまさんに対して火種を投入云々というのは言い過ぎかもしれませんが
新宿の翼さんの態度は明らかに喧嘩を売ってるように見えると思います。
新宿の翼 さんが書きました:
softya(ソフト屋) さんが書きました:
あとインデントはきれいに書きましょう。バグのもとです。
これもまったく意味がわかりません。
確かに例で書いたものはインデントがずれていますが、
例で書いたソースは手打ちしたものです。
この掲示板、Tabキーでスペース空きませんよね?
わざわざスペースキーをトントン押して書くしかないわけです。
ソースをコピペで貼り付けたわけではないので。
スペースキーをとんとんと地道に打たなきゃならない時点で、
あくまで例として説明したいものなんですから
てきとーなところで切り上げますって。
それを「インデントは揃えましょう」って言われても、、、、
デートに着ていく服はこれでいいですか?ってその服を着た写メを見せたときに
服だけ見てもらいたいからって寝癖頭で写メ取ったら
「寝癖は直しましょうね」って注意された感じなんですが。
「いやいや、んなことはわかってるって」って答えますよね。
結局、僕の質問に対し、まったく的を射た答えがないですよね?
副管理人という役職をお持ちみたいですが大丈夫ですか?
これは回答してくださったsoftya(ソフト屋)さんに対して非常に失礼だと思うのですが。
質問者の要求に合わない回答をしたからってまるで
「そんな事分かってんだからどうでもいいだろ」
「こんなのが副管理人で大丈夫なのか?」
と言いたげな発言が許されるのでしょうか?
Re: aの初期化がcaseラベルによって行われませんでしたとは?
Posted: 2014年8月21日(木) 01:01
by ISLe()
この掲示板に書き込む人の多くは、人権を侵害するような行為が平然と行われることがふつうにあって当たり前だと思っている方ばかりなのでしょうか。
知識がないなら書き込むな、素人なら書き込むな、そんなふうに言っていると受け取る方が多いことがこの掲示板の雰囲気を形作っていると感じます。
わたしが不満に思っているのは、
回答者が曖昧な回答をするせいで→たくさんのトピックが無用の長物になっている
ことであって
回答者が曖昧な回答をしても→いくつかのトピックは有用である
ことについては何の不満もありません。
このトピックについてもかずまさんの指摘によって有用となったとわたし個人は考えます。
ここはあいかわらずですね。
態度を改めない質問者と正当化しようとする回答者の何が違うのかわたしには分かりません。
Re: aの初期化がcaseラベルによって行われませんでしたとは?
Posted: 2014年8月22日(金) 00:09
by zeek
で、質問者は理解されたんでしょうかね?
解決もチェックされないままだ。
ちなみに、今回のエラーの本質的な内容は switch case 固有の話ではなく、「初期化をもつ宣言文を飛び越してその識別子の有効範囲に行ってはダメよ」という C++ 規格に従った code ではないことにありますね。
だから
コード:
int main()
{
goto BBB;
AAA:
int a = 0;
BBB:
return 0;
}
もエラーにすべきですが、VC++ はエラーにしないんですよね。
だから
> aの初期化がcaseラベルによって行われませんでしたとは?
に対して VC++ は、「規格に従った解釈でエラーにしている」かどうかはわかりませんねぇ~。
Re: aの初期化がcaseラベルによって行われませんでしたとは?
Posted: 2014年8月22日(金) 00:40
by ISLe()
'identifier' の初期化が 'goto label' によって行われませんでした。
コンパイラ エラー C2362
'identifier' の初期化が 'case' ラベルによって行われませんでした。
コンパイラ エラー C2360
'identifier' の初期化が 'default' ラベルによって行われませんでした。
コンパイラ エラー C2361
Re: aの初期化がcaseラベルによって行われませんでしたとは?
Posted: 2014年8月22日(金) 01:01
by zeek
なるほど、言語拡張を無効にすれば、ちゃんとエラーにするんですね。
感謝です。