ドラマ 『Chef~三ツ星の給食~』(天海祐希)
ネタバレ注意です。三ツ星レストランのシェフが、レストランをクビになり、小学校の給食調理員になります。自分が納得する料理を作るため、さんざん子どもたちを待たせて、出した料理は、子どもたちの口にはまったく合いませんでした。そこまで不味いっていうのかあ。。。まあ味覚の違いは人それぞれ。大人と子供だけでなく、何を食べて生きてきたかでも味覚って異なりますよね。不味くて食べられたものじゃない味でも、人によっては至高の味だったり。納豆とかチーズとか、まさに好き嫌いあるかなあと思います。私も子供の頃は、イナゴを好んで食べてましたし。今は、目が合うと可哀想に思えるので、食べるのは無理ですが。
ソフトウェアの世界でも、ある人から見ると最高のソースコードでも、別の人から見ると下手過ぎてどうしようもないソースコードだったりすることがあるようです。先日、NetBSDとGNUのソースコードを、誰が作ったのかは伏せて隣人ベテラン技術者に見せたら、「こんな下手なソースコードよく書けるなあ。新人が書いたの?」と言ってました。高級ワインを格安ワインと偽って飲ませて、文句を浴びせられた感じでしょうか。美味しいと言って欲しい!
今回は、NetBSDとGNUの、同じ関数ではあるが、異なるソースコードを見ていきます。
まずはNetBSD。ソース取得のためCVSインストールから。
$ su - # apt-get install cvs (省略) # export CVSROOT=:pserver:anoncvs@anoncvs.NetBSD.org:/cvsroot # cvs login
anoncvsと入力します。
そしてチェックアウト。
# netbsdsrc$cvs co src
チェックアウトは時間がかかりました。
今回は、strcmp関数を比較対象にします。
root@deb83:/usr/src/netbsd# find -name strcmp.c ./src/common/lib/libc/string/strcmp.c root@deb83:/usr/src/netbsd#
ついでに行数を確認します。
root@deb83:/usr/src/netbsd# !! | xargs wc -l find -name strcmp.c | xargs wc -l 67 ./src/common/lib/libc/string/strcmp.c root@deb83:/usr/src/netbsd#
全文見てみましょう。
root@deb83:/usr/src/netbsd# !-2 | xargs cat -n
1 /* $NetBSD: strcmp.c,v 1.3 2013/07/01 20:51:59 joerg Exp $ */
2
3 /*-
4 * Copyright (c) 1990, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Chris Torek.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 #if defined(LIBC_SCCS) && !defined(lint)
37 #if 0
38 static char sccsid[] = "@(#)strcmp.c 8.1 (Berkeley) 6/4/93";
39 #else
40 __RCSID("$NetBSD: strcmp.c,v 1.3 2013/07/01 20:51:59 joerg Exp $");
41 #endif
42 #endif /* LIBC_SCCS and not lint */
43
44 #if !defined(_KERNEL) && !defined(_STANDALONE)
45 #include <assert.h>
46 #include <string.h>
47 #else
48 #include <lib/libkern/libkern.h>
49 #endif
50
51 #undef strcmp
52
53 /*
54 * Compare strings.
55 */
56 int
57 strcmp(const char *s1, const char *s2)
58 {
59
60 _DIAGASSERT(s1 != NULL);
61 _DIAGASSERT(s2 != NULL);
62
63 while (*s1 == *s2++)
64 if (*s1++ == 0)
65 return (0);
66 return (*(const unsigned char *)s1 - *(const unsigned char *)--s2);
67 }
strcmpの処理は56行目からですね。面白いのは、63行目のs1とs2のポインタの進め方が異なるという点です。文字列を1文字ずつ順に比較していき、NULLまで一致していることが確認できたら0を返します。それ以外は、不一致の文字コードの差分を戻り値にしています。
この辺りは、manの説明ではこのようにあります。
STRCMP(3) Linux Programmer's Manual STRCMP(3)
名前
strcmp, strncmp - 二つの文字列を比べる
書式
#include <string.h>
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
説明
strcmp() 関数は二つの文字列 s1 と s2 を較べる。 この関数は、 s1 が s2 に較べて 1)小さい、2)等しい、3)大きい
場合に、 ゼロよりも 1)小さい、2)等しい、3)大きい整数を返す。
strncmp() 関数は、s1 と s2 の最初の n バイトだけを比較する ことを除けば、strcmp()と同様である。
返り値
strcmp() 関数と strncmp() 関数は整数を返す。 この整数は、ゼロよりも、1)小さい、2)等しい、3)大きいのいずれ
かである。 それぞれは、s1(または、この文字列の最初の n バイト)が s2 よりも、1)小さい、2)等しい、3)大きいに
対応している。
次は、GNU版を見てみます。同じファイル名を探して、癖のように行数もチェック。
root@deb83:/usr/src/glibc# find -name strcmp.c ./string/strcmp.c root@deb83:/usr/src/glibc# !!|xargs wc -l find -name strcmp.c|xargs wc -l 46 ./string/strcmp.c
では全文表示しましょう。
root@deb83:/usr/src/glibc# !-2|xargs cat -n
1 /* Copyright (C) 1991-2014 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>. */
17
18 #include <string.h>
19 #include <memcopy.h>
20
21 #undef strcmp
22
23 /* Compare S1 and S2, returning less than, equal to or
24 greater than zero if S1 is lexicographically less than,
25 equal to or greater than S2. */
26 int
27 strcmp (p1, p2)
28 const char *p1;
29 const char *p2;
30 {
31 const unsigned char *s1 = (const unsigned char *) p1;
32 const unsigned char *s2 = (const unsigned char *) p2;
33 unsigned char c1, c2;
34
35 do
36 {
37 c1 = (unsigned char) *s1++;
38 c2 = (unsigned char) *s2++;
39 if (c1 == '\0')
40 return c1 - c2;
41 }
42 while (c1 == c2);
43
44 return c1 - c2;
45 }
46 libc_hidden_builtin_def (strcmp)
こちらは、関数の引数をそのまま使わないのですね。比較の一つ一つは、文字列ではなくキャラの比較だと分かるようにc1,c2という変数に入れ直しています。判定に関しては、NetBSDと逆、つまり、一致判定よりもNULLチェックの方が先になっています。判定は、40行目の計算式におまかせする形です。
同じ関数なのに、随分考え方が異なっていますね。しかし、どちらも洗練されていて、読むのがわくわくするソースコードだと思います。
凡人な私の料理だとどうなるでしょう。自作してみます。
1 #include <stdio.h>
2
3 int my_strcmp(const char *s1, const char *s2)
4 {
5 while(*s1 == *s2)
6 if(*s1 == 0)
7 break;
8 else{
9 s1++;
10 s2++;
11 }
12
13 return (int)*s1 - (int)*s2;
14 }
15
16 #define S1 argv[1]
17 #define S2 argv[2]
18
19 int main(int argc, char* argv[])
20 {
21 printf("S1=%s S2=%s : return=%d\n",S1, S2, my_strcmp(S1,S2));
22
23 return 0;
24 }
それぞれのプログラマーをシェフだとすると、NetBSDもGNUも一流のレストランであることには違いありません。一流だからこそ、こだわりが出てくるんだと思います。


コメント