- PR -

C の localtime() の引数は混乱を招く。

投稿者投稿内容
未記入
会議室デビュー日: 2004/09/18
投稿数: 4
投稿日時: 2004-09-19 00:21
コブラさん

ポインタってややこしいですよね。
考え方ですが、以下のように考えたらどうでしょう。

今、与えられた2つの引数の値を交換するswap関数を考えます。
ありがちな解答としましては
コード:
static void swap1(int p,int q)
{
	int t;
	
	t = p;
	p = q;
	q = t;
}


ですが、これではちゃんと動作しないですよね。
正しくは
コード:
static void swap2(int *p,int *q)
{
	int t;
	
	t = *p;
	*p = *q;
	*q = t;
}


となりますよね。
これと同様に、2つのintポインタの値を交換したければ
コード:
static void swap3(int **p,int **q)
{
	int *t;
	
	t = *p;
	*p = *q;
	*q = t;
}


となりますよね。
これらは一般化できて
コード:
/*data_typeには自分が使いたい型を指定する*/
typedef int* data_type;
static void swap4(data_type *p,data_type *q)
{
	data_type t;
	
	t = *p;
	*p = *q;
	*q = t;
}


となりますよね。
この形を参考にされてはどうでしょうか。

なんかわかりにくい説明ですみません。
ちいにぃ
大ベテラン
会議室デビュー日: 2002/05/28
投稿数: 244
投稿日時: 2004-09-19 03:42
引用:

素直に func(p); とやってしまうと、ポインタ型とポインタへのポインタ型で
「互換性が違う」と通常は怒られますが、ここでポインタに & 付けるとは・・・
この使い方は初めて見ます。これは、余り教科書に載ってない。



えと、標準ライブラリだと、stdlib.h の stdtod, strtol, strtoul がこういう
引数を取ってますね。なので、その説明も参考になるかと。
(ってか、自分はこれをみて、こういう使い方を覚えたような気がします)
ちいにぃ
大ベテラン
会議室デビュー日: 2002/05/28
投稿数: 244
投稿日時: 2004-09-19 04:06
引用:

てゆーか、time_t型は ANSI C で出てきたものだろうと思います。
手元には K&R 第1版も無いので確かなところは分かりませんが...


手元の詳説C言語(1989, 原書は1987の2nd Edition)をみると、ANSI Cで出てきたものらしいです。
UNIX System V では time() は long を返していて、それを unsigned long で受け取ること、
とあります。

そこそこ良い本だと思うのですが、最新版 (C: A Reference Manual) が訳出されていないのが残念。

★訂正「原書は1997」→「原書は1987」

[ メッセージ編集済み 編集者: ちいにぃ 編集日時 2004-09-22 00:28 ]
コブラ
ぬし
会議室デビュー日: 2003/07/18
投稿数: 1038
お住まい・勤務地: 神奈川
投稿日時: 2004-09-21 14:09
コード:
static void swap3(int **p,int **q)
{
	int *t;
	
	t = *p;
	*p = *q;
	*q = t;
}



えぇえぇ、おっしゃりたい事はよく解ります>未記入氏
右辺と左辺でアドレッシングのレベルを等価にしろ、と・・・ええと、
間接のホップカウント数を揃えるっちゅぅか、、同じ型として扱えるように指定しろ、と。。。

確かに *, **, *** 並べると見栄えが悪い。

コード:
typedef int* data_type;
static void swap4(data_type *p,data_type *q)
{
	data_type t;
	
	t = *p;
	*p = *q;
	*q = t;
}



これは、イイっすね。
なるほど、常に隠されたポインタ一個くっついてるんで、表面上は殆ど普通のポインタ変数
と変わらん。

strtod, strtof, strtold 見ました。
文字列を浮動小数点数値、固定小数点数値に変換するのにここまでやる必要があるのか、
とも思いますが、、 atol とか ltoa はこんなことしてないのに。。。
コブラ
ぬし
会議室デビュー日: 2003/07/18
投稿数: 1038
お住まい・勤務地: 神奈川
投稿日時: 2004-09-21 14:26
自分では、C++ でなくても C でも OOP できる という信念があったので、未記入氏の
オリジナル・ソースをいじくって構造体に「関数へのポインタ」を含めて「クラスもどき」
を創ろうとしましたが、自分でも訳の判らぬモノが出来上がってしまいました。

コード:
#include <stdio.h>
#include <stdlib.h>

static void foo(char** const pp);

typedef struct S {        // クラス S
    void (*instance)(char *);
    char *p, **pp;
} s;

char* op="/bin/sh";

int main(void)
{
    s instance;           // インスタンス変数
    int *ret;

    printf("Size Of : %d,%d\n", sizeof(struct S), sizeof(int *));
    instance.instance = (void *)&foo;
    instance.instance((char *)&instance.p);  // 参照引数付きコンストラクタ
    (void)printf("%c\n", *instance.p);
    *instance.pp = instance.p;
    **instance.pp = 'C';
    (void)printf("%c\n", *instance.p);
    free(instance.p);     // デストラクタ
    instance.p = (char*)NULL;

    ret = (int *)&ret + 12;
    ret = (int *)&ret + 4;

//    ret = (int *)&ret + 4;
    (*ret) = (int)op;

//    exit(0);
}

void foo(char** const pp)
{
    if(pp){
        *pp = (char*)malloc(sizeof(char));
        if(*pp){
            **pp = 'A';
        }
    }

//    pp = (char **)pp + 4;
//    pp = (char **)pp + 1;
}

未記入
会議室デビュー日: 2004/09/18
投稿数: 4
投稿日時: 2004-09-22 00:09
コブラさん

示して頂いた例とは違いますが、コンストラクタ・デストラクタを実装するなら以下のような感じではいかがでしょう。

※簡単にするため色々省略してます
コード:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct tagClass{
	char *str;
}Class;

void constructor(Class *class,char *s)
{
	class->str = strcpy(malloc(strlen(s)+1),s);
}
void destructor(Class *class)
{
	free(class->str);
}
int main(void)
{
	Class instance;
	
	constructor(&instance,"aiueo");
	puts(instance.str);
	destructor(&instance);		
	return 0;
}

ほむら
ぬし
会議室デビュー日: 2003/02/28
投稿数: 583
お住まい・勤務地: 東京都
投稿日時: 2004-09-22 01:00
ども、ほむらです。
----------
ぽんす氏
(ごめんなさい。レスしたつもりでいました。_| ̄|○)

>Ancient Unix でカレンダー時刻を格納していたのが int time[2]
>であったことの名残ではないかと思います。

なるほど、今で言うところの2038年問題?対策といったところでしょうか?
8bitじゃ桁数がたりねーみたいな(笑


コブラ氏
C++で言うところのメンバ関数は暗黙的に第一引数として
暗黙的に自分自身へのポインタが渡されているにすぎないのですから
defineでそれっぽいものを作ってしまうのが一番良いかもしれませんよ。
(たしかCOM+がこんな感じだったかと。)

さすがに型チェックとか隠蔽なんて無理だし、かっこわるいですけどね。
たとえば
コード:
#define RECT_CALL_point_check(r,x,y) rect_point_check(r,x,y)

typedef struct tagRECT {
  int x;
  int y;
  int w;
  int h;
} RECT

int rect_point_check(RECT *this, int x, int y)
{
  return 0;
}

void  main()
{
  RECT rc={1,1,20,30};

  RECT_CALL_point_check(&rc,20,10);
}



こんな感じに。

あとは、もし、関数のポインタを使うときはtypedefで型宣言しておいた方がよいです。
typedef void (*)(char *) FUNC_FOO;
みたいに(微妙に違うかも)

動的に差し据える必要のあるもの以外では使わない方がいいですけどね。
コブラ
ぬし
会議室デビュー日: 2003/07/18
投稿数: 1038
お住まい・勤務地: 神奈川
投稿日時: 2004-09-22 11:31
ちょっと、私の前の例はスタック破壊してました(爆)
こっちが正解です。

コード:
#include <stdio.h>
#include <stdlib.h>

void foo(char ** const);
void destructor(char **);
void disp(char **);

typedef struct S {        // クラス S
    void (*instance)(char *);
    void (*delete)(char *);
    void (*method)(char *);
    char *p, **pp;
} s;

int main(void)
{
    s instance;           // インスタンス変数
    int *ret;

    instance.instance = (void *)&foo;
    instance.instance((char *)&instance.p);  // 参照引数付きコンストラクタ

    instance.method = (void *)&disp;
    instance.method((char *)&instance.p);   // メソッド

    (instance.pp) = &(instance.p);
    **instance.pp = 'C';

    instance.method((char *)&instance.p);   // メソッド

    instance.delete = (void *)&destructor;
    instance.delete((char *)&instance.p); // デストラクタ

    instance.p = (char*)NULL;
}

void foo(char** const pp)
{
    if(pp){
        *pp = (char*)malloc(sizeof(char));
        if(*pp){
            **pp = 'A';
        }
    }
}

void disp(char ** const pp)
{
    printf("%c\n", **pp);
}

void destructor(char** pp)
{
    free(*pp);
}



もう、ここら辺が私の限界らしいです (プ
ポインタもトリプルまでは自分で理解できない事がわかりました。

ほむら氏:
 ポインタ渡さんでも #define のラベルで実体呼んでくれる、、これ自分向きですわ。
 解り易い。
typedef 宣言は、エラーが出てしまいました・・・


未記入氏: のサンプルは、これ、後スコープ演算子ついたらもう殆ど C++ と変わりないですな。
しかし、「継承」「多重継承」「インターフェース」とかは、やっぱ C++ ならでわ、
ですか・・・

「データをどう見せるか」がオブジェクト指向ならば、メソッドでも普通の関数でも
あんまり変わらんような気がしてきました。

スキルアップ/キャリアアップ(JOB@IT)