C言語で、こんなプログラミングができたらなぁ

[戻る]
まに 2008/12/01(月) 20:00:40
お世話になります。
C言語(およびC++)で、こんなプログラミングができたら…
と、かねてより夢想してることがあります。
「こんなこと、できるわけねぇだろ!」とツッコまれそうな
アホな内容ばかりかとは思いますが、
もしかしたら自分が知らないだけで出来ることもあるかも…?
という淡い期待を込めて、書きこんでみます。
なお、開発環境は、VC++2005です。



●その1
static変数の、外部からの強引な設定・参照

値を保持したいが、通常はその関数内でしか使わない変数の場合、
グローバル変数にするより、static宣言をして静的変数にします。
(その方が、カプセル化されて分かりやすくなるので)
しかし、ごく稀に、その変数を、関数の外から設定・参照したいことがあります。
(特に、初期化させたい時)
このように、「普段はその関数の中でしか使わないが、
ある特別な記述をすることで、外部からも設定・参照が可能になる」
そんなことって、出来ないものでしょうか…?

現状、関数に引数を設けて、その値によって初期化させてますが、
わざわざそんなことのために引数を設けるのも…と思ったものでして…



●その2
強力なbreak文

2重ループの中からいっきに抜け出したり、
doループ内のswitch分のcase処理からdoループを抜けたりと…
そんな、強力な機能を持ったbreak文が、あったらいいなぁ…と思うことがあります。
goto文でも可能ですが、さすがにそんなことのためにgoto使いたくはないですし…



●その3
引数を渡さなくて済むinline関数

以下のような機能を持った関数(といっていいか分かりませんが)を、
定義することって、出来ないものでしょうか?

・inline関数のように、コードが呼び出し元の場所にそのまま展開される。
・呼び出し元のローカル変数を、引数渡しすることなく、そのまま設定・参照できる。
・関数の中に記述し、その関数からしか呼ぶことができない。

たとえば、こんな感じです。

int  function()
{
    int   a, b, c, d, e;
    sub_function();
    return a;

    void   sub_function()
    {
        // この中で、変数a〜eをそのまま使える
       a = b + c * d / e;
    }
}

これをコンパイルすると、↓のように展開される。

int  function()
{
    int   a, b, c, d, e;
    a = b + c * d / e;
    return a;
}

要するに、「コードをそのまま、別の場所に記述したい」ということです。
そうできた方が、プログラムがスッキリすることがあるので。



●その4
if文の処理内からの、else処理の実行

if〜else文は、「真の時の処理」か「偽の時の処理」か、
どちらかしか行うことはできません。
これを、「真の時の処理」を行いつつ、「偽の時の処理」も行いたい。
そんな、if〜elseの流れを変えるような、欲張りなif〜else文が、あったらいいなぁ
と思うことがあります。

たとえば、こんな場合です。

    bool    flg = FALSE;
    if ( 判定A ) {
        if ( 判定B ) {
            処理A
            flg = TRUE;
        }
    }
    if (flg == FALSE) {
        処理B
    }

判定Aと判定Bがともに真の時のみ、処理Aを行い、それ以外の場合は処理Bを行いたいわけ
ですが、
このような場合は、Flg変数を使用するしかありません。
判定Aと判定Bを一つのif文にできればいいのですが、
それぞれの判定文が長かったり、判定Aと判定Bの間に何かの処理があったりすると、そう
もいきません。
しかし、そのためにFlg変数を設けるのも、避けたいとこです。

そこで、たとえば、if_if文とelse_go文というのがあって、
「else_go文を実行すると、その外側のif_if文に対応するelse文(またはelse if文)へ
ジャンプする」
なんてのが、あったらいいなぁ、と思います。
つまり、こんな感じです。

    if_if ( 判定A ) {
        if ( 判定B ) {
            処理A
        }
        else else_go;
    }
    else {
        処理B
    }

さらには、こんな場合にも…

    bool   Flg = FALSE;
    if      ( 判定A ) { Flg = TRUE; }
    else if ( 判定B ) { Flg = TRUE; }
    else if ( 判定C ) { Flg = TRUE; }
    if (Flg == TRUE) {
        処理A
    }

こう書くことができるとか。

    if_if (TRUE) {
        if ( 判定A ) else_go;
        if ( 判定B ) else_go;
        if ( 判定C ) else_go;
    }
    else {
        処理A
    }

スパゲッティプログラムになりえるかもしれませんが、
うまく使えば変数を使わなくても済むようになると思います。




上で記述したようなことそのままでなくても、
「こんな方法があるよ」など、ご存知でしたら、
お教えいただけましたら幸いです。

aetos 2008/12/02(火) 01:14:52
> static 変数の、外部からの強引な設定・参照
static 変数に限った話ではないような。
C++ の場合、関数内 static 変数はクラスのインスタンス境界を越えて有効であるなど
の問題があるので、あまり使いませんね。
個人的に、関数内変数を関数外から初期化したいという需要自体がないですが、クラス
化してメンバ変数にすればいい気がします。

> 強力なbreak文
Java ではできますね。
ただ、そんなにループや switch がネストすること自体が危険な兆候なので、関数化し
て外部にくくりだすとかを検討したほうがいいかもしれません。

> 引数を渡さなくて済むinline関数
C++ なら、Boost を使えば出来るかも。
あるいは、来年中に出る(らしい)新規格である C++0x なら可能かも。
その辺は詳しい方にお任せします。

> if文の処理内からの、else処理の実行
break の話もそうなのですが、ご自身でも
> スパゲッティプログラムになりえるかもしれませんが、
と書かれているように、フロー制御があまり複雑になるようなら、小さな単位に切り分
けた方がいい場合があります。

aetos 2008/12/02(火) 01:18:14
> 関数内 static 変数はクラスのインスタンス境界を越えて有効であるなど

あと、オーバーロードとも相性悪いですしね。

wclrp ( 'o') 2008/12/02(火) 07:42:52
●その1

実現させるとしたらstatic変数のスコープを関数内からファイル内に置き換えることにな
るかな。
C++だとクラスでカプセル化できるから必要ないな。

static x = 5;

void set(int newX)
{
    x = newX;
}

int get()
{
    return x;
}

Ban 2008/12/02(火) 08:45:19
> static 変数の、外部からの強引な設定・参照

私も必要性がよくわかりませんので、外してるかもしれませんが、
関数内でなくソース内のstaticにすれば、
同じソース内に書いた関数だけから設定できるのでは?
C++なら無名namespaceも考えるなり、クラスにするなり、friend指定するなり、
そんなかんじでしょうか。

> 強力なbreak文
goto文なんてそんなことくらいにしか使わないの方が近い気も。

> 引数を渡さなくて済むinline関数

関数内関数は、structを定義してoperator()を作れば、
inline展開もできえますね(実際に展開されるかはコンパイラ次第ですが)

int  function()
{
    int   a, b, c, d, e;

    struct sub_function
    {
       void   operator ()()
       {
       // 但し引数もなしにここでaやbに触れることはできないはず?
       }
    } sub_function;
  
    sub_function();
    return a;
}

boostにしても関数内でのclass/templateの制限とかもあって多分難しいと思いますが…。

本当に引数なしで参照したいなら、#define - #undefしかないのでは。
# こんなことで見やすくなるのかには疑問の余地がありますけど。

> if文の処理内からの、else処理の実行

「構造化」をわざわざ崩す必要性が理解できません。

> それぞれの判定文が長かったり、判定Aと判定Bの間に何かの処理があったりすると、
> そうもいきません。
> しかし、そのためにFlg変数を設けるのも、避けたいとこです。

個人的には、積極的に判定Aと判定Bを意味のあるbool変数にでも入れておき、
その後に分岐することを考えますが、Flagという名前が悪いのでは?

というか、短絡評価を考えれば、提示例は以下と一緒?

if ( 判定A && 判定B )
{
    処理A
}
else
{
    処理B
}


if ( 判定A && 判定B && 判定C )
{
  処理A
}

仲澤@失業者 2008/12/02(火) 11:39:46
> static変数の、外部からの強引な設定・参照

あんまりやらんほうが良いかも。
参照用の関数を設ければ何でもできますけどね。

> 強力なbreak文

自分なら return してしまいます。ちょ〜強力だし(笑)。

> 引数を渡さなくて済むinline関数

_asm 使えばかけますよ。たぶん

> if文の処理内からの、else処理の実行

自分なら比較順を変えるだけで済ませます。
   if( 判定B ){
       if( 判定A )    処理A
       else           処理B
    }
    else{
        処理B
    }
かな、間違ってるかも。

金魚ちゃん 2008/12/02(火) 14:26:14
僕なりの考えもどうぞ。

>●その1
>static変数の、外部からの強引な設定・参照
ファイルのスコープ内にstatic変数を置く。
そして初期化関数と実行関数の2つに分ける。
C++では関数内に滅多にstatic変数を置かない。(置くべき時に置く)

>●その2
>強力なbreak文
goto文で分かりやすく統一。

>goto文でも可能ですが、さすがにそんなことのためにgoto使いたくはないですし…
この考え方は、何が何でもgoto文を使うなという人の意見みたいだね。
僕の考えでは多重ループで一気に多重ループを抜けるときこそ
goto文を使うべきと思っている。

>●その3
>引数を渡さなくて済むinline関数
この場合はマクロ関数を使う。
なお、マクロ関数名は全て大文字にする(例:SUB_FUNCTION()とか)

>要するに、「コードをそのまま、別の場所に記述したい」ということです。
>そうできた方が、プログラムがスッキリすることがあるので。
inlineを付けても必ず呼び出し場所にコードに展開されるか分からんよ。
だから確実に展開して欲しいならマクロ関数を使う。

>●その4
>if文の処理内からの、else処理の実行
if-else文を見直す方が先だね。

>if_if (TRUE) {
>    if ( 判定A ) else_go;
>    if ( 判定B ) else_go;
>    if ( 判定C ) else_go;
>}
>else {
>    処理A
>}
この場合は
if ( 判定A || 判定B || 判定C ){
  処理A
}
とできるね。

>if_if ( 判定A ) {
>    if ( 判定B ) {
>        処理A
>    }
>    else else_go;
>}
>else {
>    処理B
>}
この場合は
  if ( 判定A ){
    if ( 判定B ){
      処理A
      goto skipA;
    }
  }
  処理B
skipA:
とgoto文とラベルを活用する。
フラグを使うとか、同じ処理を複数箇所に記述するよりは分かりやすい。
また、処理Aや処理Bを関数(マクロ関数)にして記述すれば済む話だよ。

>bool   Flg = FALSE;
>if      ( 判定A ) { Flg = TRUE; }
>else if ( 判定B ) { Flg = TRUE; }
>else if ( 判定C ) { Flg = TRUE; }
>if (Flg == TRUE) {
>    処理A
>}
これに関しては条件式を工夫すれば出来る。
if ( 判定A || 判定B || 判定C ){
  処理A
}
判定A〜判定Cが長いのなら
if(判定A
|| 判定B
|| 判定C ){
  処理A
}
とか
if(判定A ||
   判定B ||
   判定C ){
  処理A
}
と記述する。

>スパゲッティプログラムになりえるかもしれませんが、
>うまく使えば変数を使わなくても済むようになると思います。
まとめるとgoto文とラベルを上手に使えば済むこと。

金魚ちゃん 2008/12/02(火) 14:29:43
関数を使って。

void func()
{
  if ( 判定A ){
    if ( 判定B ){
      処理A
      return;
    }
  }
  処理B
}

もあるね。

まに 2008/12/02(火) 21:29:06
[[解決]]
みなさん、いろいろとご意見、ありがとうございました。
やはり、こんなことって、できないのですね。
工夫でなんとかするしかないですね。

個人的には(誰でもそうかもしれませんが)、
むやみにクラスや関数や変数を増やしたくないんです。
goto文も、使うこと自体に抵抗があるわけではないのですが、
「ラベルをあまり配置したくない」という考え方を持っています。
なんとなく…ですけど。

「いかに、関数や変数を増やすことなく、シンプルに書くか?」
ということに苦心することがあるので、
「こんなふうに書ければいいなぁ」と思って
書き込みさせていただきました。


> C++ なら、Boost を使えば出来るかも。
> あるいは、来年中に出る(らしい)新規格である C++0x なら可能かも。

BoostやC++0xなるものは、初耳でした。
C++も、まだまだこれから発展していく言語だったんですね。
勉強になりました。


> 関数内関数は、structを定義してoperator()を作れば、
> inline展開もできえますね(実際に展開されるかはコンパイラ次第ですが)

やってみましたが、引数を渡さないとコンパイルエラーになりました。


> _asm 使えばかけますよ。たぶん

_asmって、アセンブリ記述ですよね…?
何故これでできるのかがちょっとよく…


> >引数を渡さなくて済むinline関数
> この場合はマクロ関数を使う。

マクロ関数も一つの手ですね。
ただ複数行に及ぶ場合は、末尾に「\」を記述しなくてはならないのがどうも…
一応、一つの手としては、候補に入れてみます。


> ●その3
> 引数を渡さなくて済むinline関数

C++に、BASICのGousb〜Return文があれば、それを使いたいところですが…
ないですよね?きっと…。
「gotoでジャンプして、gotoで元の場所に戻る」でも可能ですが、
それだと戻り先にラベルを記述しなくてはならないので、
メリットが希薄になってしまうんですよね…。


> 判定A〜判定Cが長いのなら
> if(判定A
> || 判定B
> || 判定C ){
>   処理A
> }
> とか
> if(判定A ||
>    判定B ||
>    判定C ){
>   処理A
> }
> と記述する。

一つのif文を複数行に分けるのも、個人的に好きではありません…
それだったら、Flg変数を使った方がいいかな…


「変数を極力使わない」という信念は捨てて、「使うべき時には使う」ようにします。
アホみたいな要望に、真面目に答えてくださってありがとうございました。

まに 2008/12/03(水) 00:36:03
すみません。
せっかくお答えいただいた方々に対して、
「真面目に」は、余計な一言でした…。
他意はないんです。気になさらないでください…m(_ _)m

2008/12/03(水) 09:19:34
>> ●その3
>> 引数を渡さなくて済むinline関数
>
>C++に、BASICのGousb〜Return文があれば、それを使いたいところですが…
>ないですよね?きっと…。
>「gotoでジャンプして、gotoで元の場所に戻る」でも可能ですが、
>それだと戻り先にラベルを記述しなくてはならないので、
>メリットが希薄になってしまうんですよね…。

BASICのGousb〜Return文ってのが、Cでいう関数でしょう。
On A Gousb〜Returnで言うなれば、switch〜case中の関数呼び出しだったりするし。

rin 2008/12/03(水) 10:25:10
ほしいのはこんなんじゃないかな

void Foo(){

 int a,b,c;
 
 gosub LABEL;

 gosub LABEL;


 return;

LABEL:
 ...

 sub_return;
}

・Foo(){}内しか影響しない
・引数やら変数やらに手間かからない

たいちう 2008/12/03(水) 10:26:33
すでに解決済みですが、、、

> C++も、まだまだこれから発展していく言語だったんですね。

CもC++も十分洗練されていると思います。(色んな意見があるでしょうが)
自分のやりたいことが、言語の規格上実現できないときは、
多くの人はそんなことをする必要を感じない、と考えることもできるでしょう。
自分のコーディングを見直すきっかけになるのではないでしょうか。

まに 2008/12/03(水) 20:35:20
> ほしいのはこんなんじゃないかな

はい。rinさんご指摘の通りです。
一瞬、本当にsub_returnなんてのがあるのかと思って検索してしまいました…(^^;


> 自分のやりたいことが、言語の規格上実現できないときは、
> 多くの人はそんなことをする必要を感じない、と考えることもできるでしょう。

そう…なのかもしれませんね。
「その4」なんて、構造化を壊すような要望ですしね…
まぁ、「goto文」も構造化を壊す命令ですが…。

ただ、「構造化された言語が分かりやすいかどうか」は、
人それぞれだと思います。
「BASICのように気ままなプログラムが好き」って人も、いるでしょうし。
(自分もBASIC畑出身なので、そういう傾向があるかも…)
C言語自体、構造化を念頭に置いて開発された言語なのかもしれませんが、
プログラミングのポリシーって、人それぞれだと思いますから、
「どんなポリシーを持った人にも扱いやすい柔軟さ」が、
あってもいいんじゃないかな〜と思ってたりします。
まぁ、それが他の人にとっても分かりやすいかどうかは、また別の問題ですけど…

ISLe 2008/12/04(木) 16:56:26
グローバル変数やgotoを自由に使えれば解決するのにという声が聞こえる気がします。
自分は適当にカプセル化されているほうが好きなのでほとんど賛同できませんが。

わざわざ初期化関数を用意するのが面倒臭いカプセル化。
何のためのカプセル化なのでしょうか。矛盾を感じます。

わたしもVC++を使って(クロス)開発してますが、ターゲットが静的変数を使えないプラ
ットフォームなので移植では元のコードのいいかげんさが露呈します。
それをもろかぶりする立場なので構造化やカプセル化は言語に関係無いんだと常々感じ
ます。

古いスレッドには追加発言できません。