Re: Cのかきかた

観測気球

収集物の記録書庫 a data archive of collection -- collectible toys

[要旨] Twitter で見かけた yaotti さんの発言に反応してみます。C でのプログラムの書き方、私ならこうするかな、って感じですかね?
[キーワード] C,programming

« 反逆を編集したかった(BlogPet) | トップページ | ソーシャルブックマーク管理ツール bookey 0.55c版 ― 「del.icio.us」関連、同期処理回りの修正を実施 »

2008.05.31

Re: Cのかきかた

外で晩飯を食べているときに、Twitter で、以下の発言を見かけました。

C書ける人教えてください:) http://generation1986.g.hatena.ne.jp/yaotti/20080530/1212157373

Twitter / やおっち: C書ける人教えてください:) http://gener...

これは、おもしろそう。帰ったら反応しよう。ってことで、この記事を書いています。

とりあえず動くんだけど妥当な書き方なのかわからんので貼ってみる。
「ここ変な書き方してるよ!!」とか突っ込み入れてもらえると嬉しいです。

(略)

K&R 3-2
改行文字やタブ文字を\nや\tという文字そのものに変えてコピーする関数escape(s, t)を書け

Cのかきかた - yaottiの日記 - ハチロク世代

すでに多くの人が反応しているようですが、私も反応してみます。

とりあえず、自分で書いてみたコードを貼り付けておきます。

/*
 * K&R 3-2
 *   改行文字やタブ文字を\nや\tという文字そのものに変えてコピーする関数
 *   escape(s, t)を書け
 */

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


char    *
escape(char *dst, const char *src)
{
    char    *s = dst;

    while ( *src ) {
        if ( *src == '\n' ) {
            *dst++ = '\\';
            *dst++ = 'n';
        }
        else if ( *src == '\t' ) {
            *dst++ = '\\';
            *dst++ = 't';
        }
        else
            *dst++ = *src;
        src++;
    }

    *dst = '\0';

    return ( s );
}

int
test(const char *targetString)
{
    char        *result = NULL;
    size_t      sz;
    int         ret = 0;

    sz = strlen(targetString) * 2 + 1;
    result = (char *)malloc( sz );
    if ( result ) {
        memset( result, 0, sz );
        escape( result, targetString );

        printf( "<<%s>> -> <<%s>>\n", targetString, result );

        ret++;

        free( result );
    }

    return ( ret );
}

int
main( int argc, char *argv[] )
{
    const char  *testString1 = "1234\t567890\nabcdefg";
    const char  *testString2 = "1234\t\t\t\n567890\n\t\tabcd\nefg\t";
    int         ret = 0;

    ret += test( testString1 );
    ret += test( testString2 );

    return ( ret );
}

char *escape(char *dst, const char *src) が本体(今回、作成する関数)で、その後ろに書いてあるのが、テスト用のコードです。テスト用のコードとセットで用意しておいて、あとで、テスト用のコードを削除するか、コメントアウトするか、#if 0 ~ #endif で囲ったりして、リリースすることになります。

で、yaottiさんのコードを見てみる。私の書いた escape() とソース(コピー元)、ディスティネーション(コピー先)が逆になってるし、リターン値の方も違ってるけど、それはいいとして。

気になるのは main() の

    while((s[i++] = getchar()) != EOF)
	;
    if(!escape(s, t))
	printf("the length of first arg is too long!!\n");
    for (i = 0; t[i] != EOF; ++i)
	printf("%c",t[i]);

最初の EOF はいいとして、2つ目の EOF、何でこんなところで出てくるのかな? 文字列の終端は通常は '\0' です。EOF がたまたま 0 である処理系もあるけど、-1 とか、0 じゃない処理系もあります。このままだと、メモリ参照エラーで落ちてしまうかも。

あと、escape() の引数は int [] よりも char * の方がいいかも。コピー元は const で修飾しておいた方が安心。 const をつけておくと、何気にコピー元を破壊するコードを書いてしまってもコンパイル時にエラーになるので、バグを見つけやすくなります(といっても、コンパイラでもチェックできないような破壊の仕方をするコードを書いちゃうと、チェックできないですけどね)。

とりあえず、こんな感じかな。あとは他の人がすでに書いてるし。

追記

格納する変数はintではなくcharで。
K&Rは今のとこ全部intで処理してるな…なんでだろ。

書き直し - yaottiの日記 - ハチロク世代

これは getchar() のリターン値が int なのと関係があります。今は、int といえば、32ビットか64ビットであることが多いですが、むかしは16ビットだったり、8ビットだったりした環境もあるんですよ(int が16ビットな環境は今でもあります)。int は char よりビット数が多いか、最悪でも同じビット数であることが保証されるので、int を使っておけば、汎用的かも、ってことですね。こわがりすぎ。

追記 2

今時は,バッファオーバーフロー,つまり文字列のあらかじめ意図した範囲を越えて書き換えてしまうような関数は危険とみなされる.こんなご時世では,いくらK&Rの課題とはいっても,実際にやるんだったら,せめてコピー先の文字列の最大長を与えてやらないといけないような課題にすべきだろうと思う.

Cでバッファオーバーフローを起こさせないためのちょっとした工夫 - jj1bdx: life beyond Japan

ここまでやるなら strlcpy() を紹介しておくべきだ,という意見があったので,関数の名前だけ書いておく.この関数はOpenBSDに始まり多くの環境で使えるが,すべての環境で実装されているわけではない.

Cでバッファオーバーフローを起こさせないためのちょっとした工夫 - jj1bdx: life beyond Japan

ちなみに、Visual C++ (8以降) では、strcpy_s() のような _s 付きの関数が対応します。Visual C++ 6 用に書いたコードを Visual C++ 8 (Visual Studio 2005)でコンパイルしようとすると C4996 の警告(warning)が出ることがありますが、この警告が出た場合は、_s 付きの関数を使って書き直すか、バッファオーバーフロー対策を自前で行なうか、する必要があります。printf 系の関数にも _s 付きの関数が用意されています。 (関連: 「Visual Studio 2005 Beta2 の評価中 - warning C4996 の件」)

投稿者: tsupo 2008.05.31 午前 03:15 | 固定リンク | このエントリーをはてなブックマークに追加 | このエントリを del.icio.us に登録 このエントリの del.icio.us での登録状況 | このエントリを Buzzurl に追加このエントリの Buzzurl での登録状況 | このエントリをlivedoorクリップに登録 このエントリのlivedoorクリップでの登録状況 このエントリをlivedoorクリップに登録している人の数 | 酢鶏巡回中

楽天市場


プログラミング」カテゴリ内の最近の記事

品揃え豊富で安い!NTT-X Store


アマゾンわくわく探検隊

トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/6737/41376496

この記事へのトラックバック一覧です: Re: Cのかきかた:

コメント

コメントを書く




※イタズラ防止のため、メールアドレスを入力しないと投稿できません。

次からのコメント入力の手間を省くために、名前やメールアドレスをcookieに記憶しますか?


URL を入力すると、その URL にリンクがはられます。
なお、メールアドレスは公開されません。ご安心ください。


ワード

ニッセン

fujisan.co.jp

楽天市場