エラーが起きた際にNULLを返せるようにしたい
NULLはメモリアドレス0番地を意味します。NULLを返すには return NULL;
と書くのが普通です。NULLの値は0ですから要するに return 0; です。
C
1 dst = NULL;
2 return( dst );
でも結果は同じです。
dst = 'NULL';
return( dst );
で、dstにNULLをいれて返しているはずなのですが、うまくいきません
たとえば 'N' == 0x4E == 78 という整数値、即ち** 'N' は N という文字のアスキーコード値**です。
では 'NULL' は何か?普通こういう書き方はしないので return 'NULL';
を試してみると 'NULL' == 0x4e554c4c == 1314212940 であることを確認できました。'N' == 0x4e, 'U' == 0x55, 'L' == 0x4c なので説明は不要でしょう。
return 'NULL'; は return 0x4e554c4c; であり、ともかく return 0; ではありません。
なお、'\0' の値も0ですから、return '\0'; と return 0; は、結果は同じですが、'\0' と NULL では表す意味・使うべき場面が違います。この場合 return '\0'; は誤った使い方なので、バグです。
さて、そもそも質問者には勘違いがあるようです。
inet_ntopの仕様だと、アドレス表記がおかしいというエラーが起きた際は、NULLを返すようにしなければならない
それは inet_ntop() ではなく、inet_pton() の仕様・役割だ、ということ。
inet_ntop - ライブラリコールの説明
inet_pton - ライブラリコールの説明
質問者が作った inet_ntop() は、「cntで与えられた dstのサイズを越え」たことを判定できているので、勘違いせず・余計なことをしなければ、完成に近づいていると思います。
念の為:
- pton, ntop はそれぞれ「p(アドレス表記文字列)」と「n(アドレスのバイナリ値)」を変換する、p→n、n→p という意味の関数名
- IPv4(AF_INET固定)なら、"130.1.7.23" というテキスト形式(p形式)と、
0x17070182のような32bitのバイナリ形式(n形式)を、相互に変換する関数である
- inet_addr("130.01.7.23")もinet_addr("130.1.7.23") も、同じ0x17070182という値を返すという事
本来の動作を確認するためにテストコードを書いてみました。
C
1#include <stdio.h>
2#include <assert.h>
3#include <arpa/inet.h> // inet_????(), struct in_addr
4#define SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
5
6int main(void)
7{
8 char* testCase[] = {
9 "130.0.7.23", "130.1.7.23", "130.01.7.23",
10 "255.255.255.255", "200.288.100.100", "0.0.0.0",
11 };
12
13 for (int i = 0; i < SIZE(testCase); i++) {
14 char *txtform = testCase[i];
15 printf("TEST \"%s\"\n", txtform);
16
17 /* テキスト形式 "XX.XX.XX.XX" からバイナリへ変換 */
18 struct in_addr in_addr = { 0xa0a05050 }; // 初期化しておく
19#if 1
20 int result = inet_pton(AF_INET, txtform, &in_addr);
21 printf("inet_pton('%s') returns %d (%s).\n",
22 txtform, result, result ? "OK" : "ERROR");
23#else
24 in_addr.s_addr = inet_addr(txtform); // エラー時は0xffffffffが返る
25#endif
26 /* バイナリからテキスト形式へ変換 */
27 char dst[16]; // 16 == sizeof "255.255.255.255"
28 const char *ptr = inet_ntop(AF_INET, &in_addr, dst, sizeof dst);
29 if (ptr) {
30 printf("inet_ntop() returns '%s'\n\n", ptr);
31 assert(ptr == dst); // dst が返るか、確認
32 } else {
33 printf("ERROR: inet_ntop() returns NULL !!!\n\n");
34 }
35 }
36 return 0;
37}
実行結果は次のようなもの。
sh
1$ ./a.out
2TEST "130.0.7.23"
3inet_pton('130.0.7.23') returns 1 (OK).
4inet_ntop() returns '130.0.7.23'
5
6TEST "130.1.7.23"
7inet_pton('130.1.7.23') returns 1 (OK).
8inet_ntop() returns '130.1.7.23'
9
10TEST "130.01.7.23"
11inet_pton('130.01.7.23') returns 0 (ERROR).
12inet_ntop() returns '80.80.160.160'
13
14TEST "255.255.255.255"
15inet_pton('255.255.255.255') returns 1 (OK).
16inet_ntop() returns '255.255.255.255'
17
18TEST "200.288.100.100"
19inet_pton('200.288.100.100') returns 0 (ERROR).
20inet_ntop() returns '80.80.160.160'
21
22TEST "0.0.0.0"
23inet_pton('0.0.0.0') returns 1 (OK).
24inet_ntop() returns '0.0.0.0'
"130.01.7.23"、"200.288.100.100" をエラーにしているのは inet_pton() です。
念の為:エラー時、inet_ntop() が返した "80.80.160.160" は、in_addr.s_addr の初期値 0xa0a05050 が変換されたものです。
この動作確認プログラムは
- #if 1 を #if 0 に変更すれば inet_addr() を使う
- char dst[16]; を、たとえば char dst[14]; に変更すれば inet_ntop() がエラーを返すことを確認できる
さらに、自作の関数をこのテストプログラムから呼べば・・・
if (p[1] == 01) ←この判定はヘン。違和感ありまくり
-
この「01」は, "130.01.7.23" の「01」と比較しようとしたのだと思う。しかし、 01 は(8進数表記であるが)要するに1という値である。つまり、if (p[1] == 1)
です。
-
重大なのは、この時点の p[1] は数字文字列 "01" ではない事。p[1] は数字文字列 "01" を変換した数値なので、意図と違う判定をしている。
-
対策すべき表記は "130.02.7.23", "130.1.07.23", "130.2.7.00", "310.1.7.23", "A30.0.7.23" 等々、様々なパターンが考えられるが、これらが全く考慮されていない。
ただし、自作の inet_pton() で全てのパターンに完璧に対応しようとしてはいけません。今の質問者の力量で無茶すると、最悪、動くプログラムを何も作れなくなります。
むしろ、最初はエラー対策を一切考慮しないプログラムを作る。正常なアドレス表記を処理できることを確認した後、できることから少しづつ対応するように修正することをお勧めしたい。たとえば
- "11.300.33.22" のように、255 を超える値があればエラーにする
- "00", "01", "02" など、0で始まる数字列があればエラーにする
但し "5.4.0.1" のように一個だけの0をエラーにしてはダメ
- "A30.0.7.23" のように数字以外の文字があればエラーにする etc.
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。