🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

3回答

2291閲覧

void型をuint32_t型にキャストしたい

ht3433

総合スコア19

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2019/11/18 02:45

編集2019/11/21 08:54

前提・実現したいこと

ネットで調べながらコーディングしてみたのですが、void型をuint32_t型にキャストしたいのですがエラーになってしまい、どう対処すればよいか困っています。
最終的にはLinuxコマンドのinet_ptonを作るつもりです。
お力添えいただければ幸いです。
宜しくお願い致します。

発生している問題・エラーメッセージ

エラー: ‘uint32_t {aka unsigned int}’ から ‘const void*’ へ の無効な変換です [-fpermissive] memcpy( dst, No.number1, 4); エラー: initializing argument 2 of ‘void* memcpy(void*, const void*, size_t)’ [-fpermissive] extern void *memcpy (void *__restrict __dest, const void *__restrict __src,

該当のソースコード

C言語

1#include <assert.h> 2#include <arpa/inet.h> 3#include <stdio.h> 4#include <stdlib.h> 5#include <string.h> 6 7 8int inet_pton(const char *src, void *dst ){ 9 10 // 変数の宣言 11 int suuti1,suuti2,suuti3,suuti4; 12 13 // 共用体の型の定義 14 union number{ 15 uint32_t number1; 16 uint8_t number2[4]; 17 }; 18 19 // 共用体の変数名の宣言 20 union number No; 21 22 // srcの文字列を数値に変換する 23 sscanf( src, "%d.%d.%d.%d", &suuti1, &suuti2, &suuti3, &suuti4 ); 24 25 // 数値に変換したものを変数に格納する 26 No.number2[0] = suuti1; 27 No.number2[1] = suuti2; 28 No.number2[2] = suuti3; 29 No.number2[3] = suuti4; 30 31 // void型のdstをuint32_t型にキャストする 32 No.number1 = ( uintptr_t )&dst; 33 34 // number1の4バイト分のメモリをdstにコピーする 35 memcpy( dst, No.number1, 4); 36 37 38 return( 1 ); 39} 40 41int main(){ 42 int result; 43 struct in_addr in_addr; 44 45 result = inet_pton("130.0.7.23", &in_addr); 46 assert(result == 1 && in_addr.s_addr == ((23<<24)|(7<<16)|(0<<8)|130)); 47 48 result = inet_pton("130.00.7.23", &in_addr); 49 assert(result == 0); 50 51 result = inet_pton("130.01.7.23", &in_addr); 52 assert(result == 0); 53 54 return(0); 55}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ht3433

2019/11/18 04:27

回答していただき、ありがとうございます。 早速ソースを拝見致しましたが、内容が難しく、あまり参考にならなかったです。 理解力に乏しく、大変申し訳ございません。
guest

回答3

0

ベストアンサー

void型は uint32_t型に変換できません。
inet_pton はコマンドではなく、関数です。
inet_pton は <arpa/inet.h> で宣言されているので
C では同じ関数は定義できません。
my_inet_pton とでもしましょう。

次のように書けばよいでしょう。

C

1#include <assert.h> 2#include <arpa/inet.h> 3#include <stdio.h> 4#include <stdlib.h> 5#include <string.h> 6 7 8int my_inet_pton(const char *src, void *dst) 9{ 10 int suuti1, suuti2, suuti3, suuti4; // 変数の宣言 11 union number{ // 共用体の型の定義 12 uint32_t number1; 13 uint8_t number2[4]; 14 }; 15 union number No; // 共用体の変数名の宣言 16 17 // srcの文字列を数値に変換する 18 if (sscanf(src, "%d.%d.%d.%d", &suuti1, &suuti2, &suuti3, &suuti4) != 4) 19 return 0; 20 21 // 数値に変換したものを変数に格納する 22 No.number2[0] = suuti1; 23 No.number2[1] = suuti2; 24 No.number2[2] = suuti3; 25 No.number2[3] = suuti4; 26 27 memcpy(dst, &No.number1, 4); 28 return 1; 29} 30 31int main(void) 32{ 33 unsigned char buf[4]; 34 int n = my_inet_pton("216.58.197.174", buf); 35 printf("%d.%d.%d.%d\n", buf[0], buf[1], buf[2], buf[3]); 36}

同じことは次のように書けます。

C

1#include <assert.h> 2#include <arpa/inet.h> 3#include <stdio.h> 4 5int my_inet_pton(const char *src, void *dst) 6{ 7 char *p = (char *)dst; 8 if (sscanf(src, "%hhd.%hhd.%hhd.%hhd", p, p+1, p+2, p+3) == 4) 9 return 1; 10 return 0; 11} 12 13int main(void) 14{ 15 unsigned char buf[4]; 16 int n = my_inet_pton("216.58.197.174", buf); 17 printf("%d.%d.%d.%d\n", buf[0], buf[1], buf[2], buf[3]); 18}

追記
質問のコード

C

1 // void型のdstをuint32_t型にキャストする 2 No.number1 = ( uintptr_t )&dst;

コメントが間違っています。
dst の型は、void型ではなく、void *、すなわち「voidへのポインタ」型です。
&dst は引数 dst のアドレスです。
&dst の型は void * *、すなわち「voidへのポインタへのポインタ」型です。
(uintptr_t) により void * * を unsigned int * にキャストしています。
No.number1 の型は uint32_t、すなわち unsigned int です。
ポインタが 4バイトのコンパイラでは、No.number1 にはそのポインタの値が入るでしょう。
ポインタが 8バイトのコンパイラでは、No.number1 にはそのポインタの値の下位32ビットが入るでしょう。
union の意味をご存知でしょうか?
No は 4バイトしかありません。
そこには、No.number2[0]~No.number2[3] に代入した値が入っています。
No.number1 への代入は、.number2 に代入した値を破壊します。
引数 dst のアドレスが No.number1 には代入されたからです。

質問のコード

C

1// number1の4バイト分のメモリをdstにコピーする 2 memcpy( dst, No.number1, 4);

memcpy の第2引数には、コピー元のアドレスを渡さなければなりません。
したがって、memcpy( dst, &No.number1, 4); としないといけません。
No.number1 = ( uintptr_t )&dst; を削除すれば、
No.number1 には .number2 に代入された値が既に入っているので、
memcpy によって目的が達成できます。

投稿2019/11/21 07:42

編集2019/11/21 14:04
kazuma-s

総合スコア8224

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ht3433

2019/11/27 01:39

回答していただき、ありがとうございます。 返信が遅れてしまい、申し訳ございません。 とても参考になり、おかげさまでなんとかうまくいきました。 本当にありがとうございました!
guest

0

以下のようにドットで区切られた4つの数値を読んでいって、数値に変換すればいいのではないでしょうか。

c

1#include <stdio.h> 2#include <ctype.h> 3 4/** 5 * @brief IPv4 アドレスを表す文字列をバイナリに変換する。 6 * 7 * @param src IPv4 アドレスを表す文字列 (例 "192.168.1.11") 8 * @param dst 変換結果 9 */ 10void inet_pton(const char *src, void *dst) 11{ 12 int i, j, v; 13 unsigned char *d = (unsigned char *)dst; 14 15 for (i = 0; i < 4; ++i) { 16 v = 0; // 文字列を変換した数値 17 18 // . で区切られた数字1つ分を読み込み、数値に変換する。 19 for (j = 0; j < 3 && isdigit(src[j]); ++j) 20 v = 10 * v + src[j] - '0'; // 整数での値 21 22 d[i] = v; 23 src += j + 1; 24 } 25} 26 27int main() 28{ 29 char *src = "192.168.1.11"; 30 unsigned char dst[4]; 31 32 inet_pton(src, (void*)dst); 33 34 // 192 168 11 1 35 printf("%hhu %hhu %hhu %hhu\n", dst[0], dst[1], dst[2], dst[3]); 36}

Wandbox の C99環境で動作確認

投稿2019/11/21 06:56

tiitoi

総合スコア21956

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

型が違うものの代入ができないといってますね
そこはどうしたい(どうなってほしい)んでしょうか

投稿2019/11/18 02:51

編集2019/11/18 02:54
y_waiwai

総合スコア88038

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ht3433

2019/11/18 04:07

回答していただき、ありがとうございます。 文字列srcをIPv4のネットワークアドレス構造体に変換したいです。 また、変換後のsrcのアドレスをstruct in_addrに変換させ、dstにコピーしたいです。
y_waiwai

2019/11/18 04:40

なら、文字列をピリオドで分割して整数変換しましょう
ht3433

2019/11/18 05:23

回答していただき、ありがとうございます。 助言を受け、コーディングしてみたのですが、行き詰ってしまいました。 もう少し具体的なアドバイスをいただけるとありがたいです。 ソースコード #include <assert.h> #include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #include <string.h> int inet_pton(const char *src,void *dst ) { union number{ uint32_t number1; uint8_t number2[4]; }; union number No; uint32_t net_No; int i = 0; // ドットを区切りに文字列を分割 // 1回目 src = strtok( number2, "."); No.number2[0] = src; // 2回目以降 while( src != NULL ){ // strtok関数により変更されたNULLのポインタが先頭 src = strtok( NULL, "."); // srcがNULLの場合、エラーが発生するので対処 if( src != NULL ){ i++; No.number2[i] = src; } } net_No = htonl( No.number1 ); // srcをIPv4のネットワークアドレス構造体に変換 src = net_No; in_addr = src; // dstにコピーする strcpy( dst, in_addr ); return( 0 ); } int main(){ int result; struct in_addr in_addr; result = inet_pton("130.0.7.23", &in_addr); assert(result == 1 && in_addr.s_addr == ((23<<24)|(7<<16)|(0<<8)|130)); result = inet_pton("130.00.7.23", &in_addr); assert(result == 0); result = inet_pton("130.01.7.23", &in_addr); assert(result == 0); return(0); }
y_waiwai

2019/11/18 06:21

なんかの課題かなんかだと思いますが。。 ・strtokの戻り値は文字列(のアドレス)ですんで、これを整数に変換する必要があります(atoi関数?) ・IPの文字列がどこにはいってるのか、変換してどの変数に入れるのか見直しなさい。このコードではムチャムチャです ・んで、strtok関数というのは元の文字列を破壊します。入力文字列をいったん別の配列にコピーしてから変換しましょう
ht3433

2019/11/18 07:14

アドバイスをしていただき、ありがとうございます。 確かにコードが無茶苦茶だったので、一度見直し、一つずつ処理を考えていこうと思います。 そこで、srcをネットワーク構造体に変換する処理がうまくいってないのですが、そのエラー内容が、 エラー: ‘uint32_t {aka unsigned int}’ から ‘const char*’ への無効な変換です [-fpermissive] src = net_No; となっており、変換ができないか調べてみたのですが、解決できませんでした。 どのようにすればよいのでしょうか? 宜しくお願い致します。 ソースコード #include <assert.h> #include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #include <string.h> int inet_pton( const char *src,void *dst ){ // 共用体の型の定義 union number{ uint32_t number1; uint8_t number2[4]; }; // 共用体の変数名の宣言 union number No; uint32_t net_No; // アドレスを変数に代入 No.number2[0] = 130; No.number2[1] = 0; No.number2[2] = 7; No.number2[3] = 23; // ネットワークバイトオーダーをポストバイトオーダーに変換 net_No = htonl( No.number1 ); // srcをネットワーク構造体に変換する src = net_No; return( 0 ); } int main(){ int result; struct in_addr in_addr; result = inet_pton("130.0.7.23", &in_addr); assert(result == 1 && in_addr.s_addr == ((23<<24)|(7<<16)|(0<<8)|130)); return(0); }
y_waiwai

2019/11/18 07:19

printf("%d.%d.%d.%d",No.number2[0],No.number2[1],No.number2[2],No.number2[3]); こういうことがしたいのかな?
ht3433

2019/11/18 07:27

いえ、私がしたいのは、文字列srcをネットワークアドレス構造体に変換させたいのであって、取得した文字列を出力することではないです。
y_waiwai

2019/11/18 07:31

srcを変換したいなら、srcに代入してる場合じゃないでしょうw
ht3433

2019/11/18 07:43

すみません、よくわからないです。 srcを変換させたいから、net_Noの中身をsrcに代入するのではないでしょうか?
y_waiwai

2019/11/18 07:48

関数のなかの各行の命令がどういう動作をしていき、各変数のナカミがどうなるかを考えてみましょう。 どうもC言語の基礎からやりなおしてもらったほうがよろしいかと。
ht3433

2019/11/18 08:04

y_waiwaiさんのおっしゃるとおり、命令がどういう動きをして、各変数の中身も考えてみたのですが、どうもよく分かりません。 なにかヒントでもいただければ幸いです。
y_waiwai

2019/11/18 08:11

src = net_No; という命令文は、net_No のナカミを src にコピーする、という動作になります しかし、双方の変数の型が違うので、コピーしても意味がないよ、とコンパイラさんが知らせてくれています ムリヤリ実行したところで意味のあるもんにはならないです あなたの言う通り、srcからなにかに変更したいと言うなら、 net_No = 変換関数(src); という命令文となる、はず、です result = inet_pton("130.0.7.23", &in_addr); これはそうなってるでしょう
ht3433

2019/11/18 08:23

ヒントをいただき、ありがとうございます。 atoi関数を使用して、文字列srcを数値に変換しましたが、y_waiwaiさんがおっしゃりたいことはこういうことでしょうか? // srcをネットワーク構造体に変換する net_No = atoi( src );
y_waiwai

2019/11/18 08:28

まあしかし、atoi関数では、あなたの思うような変換はできないですよね。
ht3433

2019/11/18 08:40

それはどういうことでしょうか? 詳しく教えていただきたいです。
y_waiwai

2019/11/18 08:56

sscanf関数を使えばそういう動作をする関数は作れるでしょう。
ht3433

2019/11/18 09:18

回答していただき、ありがとうございます。 sscanfを使って、srcをネットワーク構造体に変換しようと思ったのですが、うまくいきません。 警告: 書式 ‘%u’ は引数の型が ‘unsigned int*’ であると予期されますが、第 3 引数の型は ‘uint32_t {aka unsigned int}’ です [-Wformat=] sscanf( src, "%u", net_No ); // srcをネットワーク構造体に変換 sscanf( src, "%u", net_No ); どうしたらよいでしょうか?
ht3433

2019/11/21 04:43

上記のコメントについては、ソースコードを新たにコーディングしたので大丈夫です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問