ドラマ 『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も一流のレストランであることには違いありません。一流だからこそ、こだわりが出てくるんだと思います。
コメント