グローバル変数の危険性を減らすために

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Shota

グローバル変数の危険性を減らすために

#1

投稿記事 by Shota » 14年前

以下のようなマクロを作りました。

コード:

; gaccess.h-------------------------------------------------------
#ifndef INCLUDED_GACCESS_H
#define INCLUDED_GACCESS_H

#include <stdio.h>

#ifdef GLOBAL_INSTANCE_DEBUG
#define CREATE_GLOBAL(TYPE, VALUE) MAKE_GLOBAL_INSTANCE_DEBUG(TYPE, VALUE)
#else
#define CREATE_GLOBAL(TYPE, VALUE) MAKE_GLOBAL_INSTANCE(TYPE, VALUE)
#endif

#define MAKE_GLOBAL_INSTANCE_DEBUG(TYPE, VALUE)\
	static TYPE *VALUE(int line){\
		static TYPE VALUE##_data;\
		fprintf(stderr ,"use global instanse '%s' in %d.\n", #VALUE, line);\
		return &VALUE##_data;\
	}
// end define
#define MAKE_GLOBAL_INSTANCE(TYPE, VALUE)\
	static TYPE *VALUE(int line){\
		static TYPE VALUE##_data;\
		return &VALUE##_data;\
	}
// end define

#define GLOBAL_ACCESS(VALUE) (*VALUE(__LINE__))

#endif
; end gaccess.h-------------------------------------------------------

コード:

こんな感じで使用します。
; main.c----------------------------------------------------------------
#include <stdio.h>

#define GLOBAL_INSTANCE_DEBUG
#include "gaccess.h"

CREATE_GLOBAL(int, x)
#define x GLOBAL_ACCESS(x)

CREATE_GLOBAL(int *, p)
#define p GLOBAL_ACCESS(p)

int main(){
	x = 5;
	p = &x;
	printf("%p %d", p, *p);
	return 0;
}
CREATE_GLOBALで定義したx,pは元は関数なのですが、変数に見立てて使用しています。
関数なので、不意に意図しないところで値が書き換えられたとしても、最後に呼ばれた行を出力することができるのでデバッグがしやすいはずです。

グローバル変数は使いたくなかったのですが、使わないとコードがとんでもなくなりそうな気がしたので、このようなマクロを定義してみたのですが、実用性はあると思いますか?
このマクロだと普通の変数と違ってこんなことができない、だとか、何か弊害があれば教えてください。


codeタグを追加しました。詳しくはフォーラムルールをご覧ください。 by softya(ソフト屋)

Shota

Re: グローバル変数の危険性を減らすために

#2

投稿記事 by Shota » 14年前

すみませんcodeで囲い忘れました。

Poco
記事: 161
登録日時: 15年前

Re: グローバル変数の危険性を減らすために

#3

投稿記事 by Poco » 14年前

このマクロだと普通の変数と違ってこんなことができない、だとか、何か弊害があれば教えてください。
グローバル変数の配列はどう定義すればいいのでしょうか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: グローバル変数の危険性を減らすために

#4

投稿記事 by softya(ソフト屋) » 14年前

初期値も問題ですね。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: グローバル変数の危険性を減らすために

#5

投稿記事 by ISLe » 14年前

わたしがグローバル変数の意味を分かっていないのかもしれませんが。
別のfoo.cというソースファイルで定義した関数からxの値を書き換えたいときはどうしたら良いのでしょう。

グローバル変数というのは、staticの付いてない外部変数だと思ってます。
最後に編集したユーザー ISLe on 2012年2月03日(金) 00:16 [ 編集 1 回目 ]

Shota

Re: グローバル変数の危険性を減らすために

#6

投稿記事 by Shota » 14年前

ポインタ型で定義して動的確保をすれば配列として機能します。
静的変数に動的確保ってのも変な感じですが。

コード:

#include <stdio.h>
#include <stdlib.h>

#define GLOBAL_INSTANCE_DEBUG
#include "./lexeropt_2/gaccess.h"

CREATE_GLOBAL(int *, ary)
#define ary GLOBAL_ACCESS(ary)


int main(){
	ary = malloc(sizeof(int)*2);
	ary[0] = 1;
	ary[1] = 2;
	printf("%d %d", ary[0], ary[1]);
	free(ary);
	return 0;
}
freeすると確保されたメモリ領域自体は解放されますが、aryはstaticなのでポインタ変数のメモリ領域はプログラム終了まで残るはずです。

Shota

Re: グローバル変数の危険性を減らすために

#7

投稿記事 by Shota » 14年前

>>ソフト屋さん
初期値用も指定できるマクロを作れば実装できなくはないですが、確かにかなりごちゃごちゃしますね。

#define MAKE_GLOBAL_INSTANCE_INIT(TYPE, VALUE, INIT)\
static TYPE *VALUE(int line){\
static TYPE VALUE##_data = INIT;\
return &VALUE##_data;\
}
// end define

>>IsLeさん
一応staticを外せば外部からも参照できます(extern、プロトタイプ宣言をするマクロでもつくり)
ただ、関数名なのでstaticを外した場合に他のファイルで他の変数として同名の変数が定義されている場合はリンクエラーになると思いますので注意が必要です。

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: グローバル変数の危険性を減らすために

#8

投稿記事 by ISLe » 14年前

検討してみましたけど、わたしはグローバル変数を使わないので実用性があるかどうか自体を判断できないですね。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: グローバル変数の危険性を減らすために

#9

投稿記事 by softya(ソフト屋) » 14年前

私なら安全性にこだわるならsetter/getter関数を使うと思います。その方が直感的ですし。
あと変数名の付け方がマズイと思わぬ名前の置き換えで困るコンパイルエラーが出そうです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

Shota

Re: グローバル変数の危険性を減らすために

#10

投稿記事 by Shota » 14年前

最初は

コード:

static int *getInstance_x(){
 static int data;
 return &data;
 }
 void set_x(int data){
 *getInstance_x() = data;
 }
 int get_x(){
 return *getInstance_x();
 }
こんな感じできちんと書いていたのですが、やはりスタンダードに書くべきですかね。
ただこれだと1つのグローバル変数のために名前空間を3つも汚すことになるんですよね。

ちなみに、どのような名前だとコンパイルエラーが起きそうですか?

#define SWAP(x, y) do { int temp = x; x = y; y = temp; } while(0)
このようなマクロの場合だとxかyにtempを指定するとエラーになるのは分かるのですが。。

Poco
記事: 161
登録日時: 15年前

Re: グローバル変数の危険性を減らすために

#11

投稿記事 by Poco » 14年前

Shota さんが書きました: ちなみに、どのような名前だとコンパイルエラーが起きそうですか?
グローバル変数と同名の変数をローカル変数として定義した時は起きますね。
#お行儀が悪いのをコンパイルエラーとして弾いていると見るべきか、このマクロ使わなければコンパイル通るのに、と見るべきか。

Shota
記事: 2
登録日時: 14年前

Re: グローバル変数の危険性を減らすために

#12

投稿記事 by Shota » 14年前

あ…確かにグローバル空間にある関数とローカル空間にある変数が衝突しますね。
これは気づいていませんでした。ありがとうございます。

具体的な問題点はこれくらいでしょうか。

アバター
h2so5
副管理人
記事: 2212
登録日時: 15年前
住所: 東京
連絡を取る:

Re: グローバル変数の危険性を減らすために

#13

投稿記事 by h2so5 » 14年前

ぽこ さんが書きました: グローバル変数と同名の変数をローカル変数として定義した時は起きますね。
#お行儀が悪いのをコンパイルエラーとして弾いていると見るべきか、このマクロ使わなければコンパイル通るのに、と見るべきか。
スコープが違うので変数名が同じでもエラーは出ませんよ。
http://ideone.com/Y9XSI


失礼。思いっきり勘違いしてました(-_-;)

Poco
記事: 161
登録日時: 15年前

Re: グローバル変数の危険性を減らすために

#14

投稿記事 by Poco » 14年前

先ほどのコメントと同じような内容ですが、
構造体のメンバとも被れませんね。

コード:

struct A {
    int * p;
};

struct A a;

CREATE_GLOBAL(int *, p)
#define p GLOBAL_ACCESS(p)

int main(){
    a.p = 4
    return 0;
}

Shota
記事: 2
登録日時: 14年前

Re: グローバル変数の危険性を減らすために

#15

投稿記事 by Shota » 14年前

構造体メンバとの重複、おそらくこれが一番痛いですね…。

グローバル変数は他と被らない長い変数名にする、だとか、接頭語としてGlobalをつけるだとかしないと実用性はなさそうですね。
その条件を満たした上でなら、この少し改良したマクロが使えそうです。

コード:

#ifndef INCLUDED_GACCESS_H
#define INCLUDED_GACCESS_H

#include <stdio.h>

#ifdef GLOBAL_INSTANCE_DEBUG
#define CREATE_GLOBAL(TYPE, VALUE) MAKE_GLOBAL_INSTANCE_DEBUG(TYPE, VALUE)
#define GLOBAL_ACCESS(VALUE) (*VALUE(__LINE__))
#else
#define CREATE_GLOBAL(TYPE, VALUE) TYPE VALUE
#define GLOBAL_ACCESS(VALUE) VALUE
#endif

#define MAKE_GLOBAL_INSTANCE_DEBUG(TYPE, VALUE)\
	static TYPE *VALUE(int line){\
		static TYPE VALUE##_data;\
		fprintf(stderr ,"use global instanse '%s' in %d.\n", #VALUE, line);\
		return &VALUE##_data;\
	}
// end define
#endif
GLOBAL_INSTANCE_DEBUGが定義されているときは関数として、定義されていないときは通常通りのグローバル変数として定義する仕様になっています。
グローバル変数を使用していてどこで書き換えられたかチェックしたいときのみGLOBAL_INSTANCE_DEBUGを定義する…などの使い方が。

まぁ、これでもやはり上記レスに挙がってる問題は解決できないのですが…。
そもそもGLOBAL_INSTANCE_DEBUGを定義しているときとしていないときで挙動が変わったら大問題ですよねorz

閉鎖

“C言語何でも質問掲示板” へ戻る