質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
C

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

Q&A

解決済

2回答

2242閲覧

pthreadについて色々関数のキャストなど、引数の渡し方が理解できません。

apeirogon0813

総合スコア117

C

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

0グッド

0クリップ

投稿2019/08/04 16:42

以下のスレッドを用いて配列a[]の合計値を求めるプログラムについて質問したいのですが

(1)pthread_createで実行させる関数はvoid *で宣言しなければいけないのでしょうか? ポインタの部分は理解できますが、voidの理由が特に理解できないです。

(2)pthread_joinで受け取れる値の型はvoidである理由がよくわかりません。

(3)関数calcの引数もvoidの意味がわかりません。calc(arg_t *arg)ではなぜいけないのですか。

(4)sum += (int)(unsigned long)ret;などの2回キャストしているのはどういう意味になるのでしょうか。sumがint型なので(int)だけすればいいと思いました。

ご教示願います。

C

1include <stdio.h> 2#include <stdlib.h> 3#include <unistd.h> 4#include <pthread.h> 5 6typedef struct { 7 int start; 8 int end; 9} arg_t; 10 11int a[10] = {-1, 23, -34, 45, 5, 6, 7, 8, 9, 10}; 12int sum = 0; 13 14void *calc(void *arg) { 15 int i, s= 0; 16 arg_t * argp = (arg_t *)arg; 17 for(i=argp->start;i<=argp->end; i++) { 18 sum+=a[i]; 19 } 20 return (void *)(unsigned long)s; 21} 22 23int main(void) { 24 pthread_t thread; 25 arg_t arg1, arg2; 26 void *ret; 27 28 arg1.start=0; arg1.end=4; 29 pthread_create(&thread, NULL, calc, &arg1); 30 31 arg2.start=5; arg2.end=9; 32 sum += (int)(unsigned long)calc(&arg2); 33 pthread_join(thread, &ret); 34 sum += (int)(unsigned long)ret; 35 printf("sum=%d\n", sum); 36 return 0; 37} 38

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

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

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

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

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

guest

回答2

0

ベストアンサー

(1)の回答
全てのケースに対応できるように考慮されているからです。
今回のケースではcalcがユーザーにとって、起動してほしいスレッドの開始の関数になります。
今回のケースではcalcにとっては、
int calc(arg_t* arg)
で定義されることが、もっとも望ましい形です。
(構造体arg_t型へのポインターを引数にとり、int型の戻り値を返す)
ところが、これは、calcにとっての都合であり、すべてのケースに当てはまりません。
例えば、文字列を引数にとり、文字列中の最後の文字のポインターを返すfuncを想定します。
"dataXYZ"が渡されたとき、Zの文字の位置のポインターを返します。
この関数funcにとって、もっとも都合の良い定義は
char *func(char *str)
のような定義になります。

そうすると、関数のプロトタイプは、作る関数毎にまちまちの定義になります。そして、それらをすべて、成立させるためには、
void *xxx(void *arg)
の形にせざるを得ないのです。

(2)の回答
これも(1)と同様です。calcのreturn で返した値が、retに設定されます。
従って、calcに限って言えば、int型の変数retを用意しておけば、そこにcalcの結果が設定されます。
ただし、それは、calcに限っての話であり、(1)のfuncにとっては、ポインター型で返すので、
ポインター型の変数を用意しておく必要があります。
その為、どのような関数でも使用できるようにする為に、void *型 を使用します。

(3)の回答
(1)で回答済み

(4)の回答
64ビットコンパイラの前提ですが、その場合の変数のサイズは以下のようになります。
int型 4バイト
long型 8バイト
ポインター型 8バイト
以下、その前提での話です。
calcが返す値は、実質的にはint型(4バイト)の整数です。
しかしながら、定義上は、void *型なので、ポインター型になり、8バイトのデータを返すことになります。
そのため、
①4バイト整数を8バイト整数に変換 (unsigned long)でキャスト
②8バイト整数をポインター型変換  (void *)でキャスト
します。

calcからは、8バイトの整数をポインター型に変換したものが返ります。(実質的には4バイトの整数の部分)従って、8バイトのポインターを4バイトの整数にするためには、
③ポインター型を8バイトの整数に変換 (insignen long)でキャスト
④8バイトの整数を4バイトの整数に変換 (int)でキャスト

ここで、C言語の規約上
ポインター型を同じサイズの整数型に変換する場合(③の場合)、結果は処理系依存であり、
ポインター型を8バイト小さいサイズの整数型に変換する場合、結果は未定義であることが記述されています。
https://kikakurui.com/x3/X3010-2003-01.htmlの型変換に関する記述を参照)
つまり、void* を いきなりint型に変換した結果は規格上未定義になります。
たぶん、INTEL系のマシンでgccコンパイラを使用した場合は、上位の4バイトが無視され、
下位の4バイトがint型の変数に格納されるはずですが(これはあなたが想定した通りですが)
規格上は、未定義です。つまり、どのような結果になっても知りませんよ、ということです。
そのため、いきなりポインター型を8バイト小さいサイズの整数型に変換せずに、
ポインター型を8バイトの整数に変換し、そのあとで8バイトの整数を4バイトの整数に変換する方法をとったほうが、規格上は安全である。
ということになります。このようにしておくと、これらのコードを別の処理系に移植する際、予期しない結果に遭遇する確率を減らすことができます。
(ポインター型を整数型に変換すること自体が処理系依存の結果なので、100%予期した結果になることが保障されているわけではありませんが、
いきなりポインター型をint型に変換するよりははるかに安全です)

投稿2019/08/05 16:21

tatsu99

総合スコア5438

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

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

apeirogon0813

2019/08/05 17:48

ありがとうございます。統一するために使われていたのですね。とても理解しやすかったです。
guest

0

(1)、(2),(3)定義でそう決められてるんで、そういうもんとして覚えておきましょう
void*はC言語では汎用のポインタ型として使われてます。サイズが合えば、キャストにより他の型も利用できます
(4)コンパイラにより、ポインタ型と違うサイズの型に直接キャストするとエラーが出たりワーニングが出たりするんで、一旦同サイズの整数型にキャストしたあと、目的の型にキャストしてますね。
そこらへんは実際にそういうコードを書いてコンパイルしてみればわかるんじゃないかと。

投稿2019/08/04 22:46

y_waiwai

総合スコア87747

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問