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

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

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

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

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

4回答

2332閲覧

C言語の標準ライブラリで戻り値がvoid*型の関数は適切に境界調整(アライメント)された値を返すことが保証されているのでしょうか?

sumachu

総合スコア22

C

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

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/01/13 12:52

表題の通り、C言語の標準ライブラリで戻り値がvoid型の関数は適切に境界調整(アライメント)された値を返すことが保証されているのでしょうか?私は新・明解C言語ポインタ完全攻略という書籍を勉強中にvoidへのポインタ型を他の型へのポインタ型(charへのポインタ型を除く)にキャストする際は、境界調整(アライメント)された値を返すことが保証される必要があることを知りました。この書籍内ではcalloc関数、malloc関数、realloc関数は適切に境界調整された値を返すことが保証されていると記載されていました。C言語の標準ライブラリにはこれ以外の関数にもvoid型を戻り値とする関数が存在します。以下は私の仮説ですが、C言語の標準ライブラリの関数で、戻り値をvoid型としているのは、汎用性を持たせるためであり、void型を他の型へのポインタ型にキャストして使用されることを想定していると考えています。その場合、C言語の標準ライブラリで、戻り値がvoid*型の関数は適切に境界調整(アライメント)された値を返すことが保証されているという記述がどこかに明記されているはずです。私の仮説が正しい場合ですが、こういった記述はどこをレファレンスすればいいのでしょうか?合わせてご回答いただけると幸いです。

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

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

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

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

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

guest

回答4

0

C言語の標準ライブラリで戻り値がvoid*型の関数は適切に境界調整(アライメント)された値を返すことが保証されているのでしょうか?

そんなわけありませんし、必要もありません。
分かりやすい例としては、void *memcpy()は第一引数をそのまま返します。

malloc等は境界調整された値を返します。
理由は下記に書いてあります。

JIS規格書より:

7.20.3

記憶域管理関数 calloc 関数,malloc 関数及び realloc 関数の連続する呼出しによって割り付けられる記憶域の順序及び隣接性は,未規定とする。割付けが成功したときに返されるポインタは,いかなる型のオブジェクトへのポインタに代入してもよいように,また(領域が明示的に解放されるまで)その割り付けられた領域のオブジェクト又はオブジェクトの配列へのアクセスに使用してもよいように,適切に境界調整されているものとする。

投稿2020/01/13 13:17

編集2020/01/13 13:19
otn

総合スコア84559

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

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

sumachu

2020/01/13 13:55

ご回答ありがとうございます。void* memcpy()の例は分かりやすいですね。境界調整する必要もありませんというのも、理解できました。そもそも、今回の疑問を抱いたのは、昇順に並んだint型の配列からある値をbsearchで探索した戻り値をint*の変数に代入するコードを見たのがきっかけでした。bsearchの戻り値はvoid*型ですが、探索対象はint型ですので、bsearchの戻り値が例えば奇数番地を指すポインタとなるはずがないということに気付きました。今回は質問を抽象化しすぎました。以後気を付けます。今後ともよろしくお願い致します。
guest

0

ベストアンサー

void *を返す標準ライブラリ関数なんて数えるほどしかないと思います。ということで、n1570(C11最終ドラフト)のAnnex Bで検索してみました。C11での標準ライブラリになります。

<stdlib.h>

C

1void *aligned_alloc(size_t alignment, size_t size);

alignmentで指定した境界サイズでアライメントされます。

C

1void *calloc(size_t nmemb, size_t size); 2void *malloc(size_t size); 3void *realloc(void *ptr, size_t size);

どんなオブジェクトでも可能なように標準的な境界サイズでアライメントされます。

C

1void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, 2 int (*compar)(const void *, const void *)); 3void *bsearch_s(const void *key, const void *base, rsize_t nmemb, rsize_t size, 4 int (*compar)(const void *k, const void *y, void *context), void *context);

sizeで配列の要素サイズを指定しており、このサイズの境界のポインタを返します。

<string.h>

void *memcpy(void * restrict s1, const void * restrict s2, size_t n); void *memmove(void *s1, const void *s2, size_t n); void *memset(void *s, int c, size_t n);

返り値は第一引数のs1またはsであり、元々の境界から変更はありません。

void *memchr(const void *s, int c, size_t n);

バイト単位で文字を探すため、1バイト区切りの境界で返ることになります。バイト検索ですので、char等のバイト単位として取り扱うべきでしょう。

<threads.h>

void *tss_get(tss_t key);

対になるtss_set()でセットしたポインタを返すため、セットしたポインタの境界になります。


ということで、質問の「適切に境界調整(アライメント)された値を返すこと」が「どんなオブジェクトのポインターにもキャスト可能なようにアライメントされていること」と言う意味であれば、答えは"NO"です。しかし、「その関数の動作の意味を踏まえて使用した場合、期待されるオブジェクトのポインターとしてキャスト可能なようにアライメントされていること」であれば、答えは"YES"です。

投稿2020/01/13 14:29

raccy

総合スコア21735

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

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

sumachu

2020/01/13 14:36

ご回答ありがとうございます。とても確かります。ご回答者様のご回答を自分でも調べることができるように精進します。
guest

0

とりあえず調べるとすればCの規格書でしょうか。

C99相当の日本語版であれば、'JIS X3010'をググれば閲覧出来るページに行き着けるはずです。

投稿2020/01/13 13:19

thkana

総合スコア7639

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

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

sumachu

2020/01/13 13:48

ご回答ありがとうございます。これからJIS規格書もリファレンスしてみます。
guest

0

アライメントするのは、変数定義するとき、領域確保するとき、です。
それ以外ではアライメントの操作はしません

投稿2020/01/13 13:01

y_waiwai

総合スコア87774

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

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

sumachu

2020/01/13 13:32

すみません。私の力不足で、回答者様のご回答の意図を理解するには至りませんでした。もう少し、具体的に質問させて下さい。(具体例に対して、具体的にご回答いただけると幸いです。)例えば、int型のオブジェクトを偶数番地を先頭に配置する2バイト境界調整する処理系を想定します。ここで、あるvoid*型を戻り値とする関数が奇数番地を指すvoidへのポインタをreturnしたとします。この返却値をint型へのポインタにキャストしようとした際、キャスト後は偶数番地を指すポインタとなる必要があります。ですので、あるvoid*型を戻り値とする関数はint型へのポインタにキャストする際は偶数番地を指すvoidへのポインタを返す必要があると考えています。この具体例の場合、C言語の標準ライブラリでvoid*を戻り値とする関数は偶数番地を指すvoid*へのポインタを返す特別な操作を関数内部でおこなっているのではないかと考えています。
sumachu

2020/01/13 13:47

度々すみません。回答者様や他の回答者様の回答を読んでいるうち、解決しました。お手数をおかけました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問