char* について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
MNS

char* について

#1

投稿記事 by MNS » 16年前

const char* string = "ABCDE" や
char* string = "ABCDE" は

char str[/url] = "ABCDE";
char* string = &str[0];

と同じことなのでしょうか?

ふと、このようなコードを見た時に、
これでは"A"の分しか確保されなのでは無いか、と思いまして。

non

Re:char* について

#2

投稿記事 by non » 16年前

同じかと問われれば、違うと思いますね。
stringに入るアドレスが、スタック領域を指すか、静的領域を指すかが違ってます。

>これでは"A"の分しか確保されなのでは無いか、と思いまして。
ちょっと、意味がわかりません。どこに確保?

たかぎ

Re:char* について

#3

投稿記事 by たかぎ » 16年前

> 同じことなのでしょうか?

違います。
どう違うかは文脈にもよりますので、前後のコードを補足してください。

MNS

Re:char* について

#4

投稿記事 by MNS » 16年前

>>nonさん
const char* の場合は静的領域
ただの char* の場合は静的もしくはスタック領域を指すということでしょうか?

>>たかぎさん
要は、
char* string = "ABCDE"
このコードを実行すると、
char str[/url] = "ABCDE";
"ABCDE"が配列のようにがどこかの空メモリにおかれ、
char* string = &str[0];
その最初のアドレス('A'のアドレス)がstring代入される
ということです。(strは適当にでっちあげたものです)

>"A"の分しか確保されなのでは無いか
'A'はどこかの空いたメモリにおかれるかもしれませんが、
"BCDE"分はメモリが空いているか空いていないか関係なく
'A'のあとの連続したところに置かれてしまうのではないか、(配列の添字を超えた時のように)
ということです。

たかぎ

Re:char* について

#5

投稿記事 by たかぎ » 16年前

> 要は、
> char* string = "ABCDE"
> このコードを実行すると、
> char str[/url] = "ABCDE";
> "ABCDE"が配列のようにがどこかの空メモリにおかれ、
> char* string = &str[0];
> その最初のアドレス('A'のアドレス)がstring代入される
> ということです。(strは適当にでっちあげたものです)

ですから、具体的にどうなるかは文脈に依存します。さらには処理系にも依存します。
また、「空メモリ」とは何でしょうか?

strがどの記憶域に配置されるか、そしてどんな結合(外部結合、内部結合、無結合)を持つか、そして、文字列の書き換え可否について考えてみてください。

non

Re:char* について

#6

投稿記事 by non » 16年前

char* string = "ABCDE"
の "ABCDE"が静的領域に確保されます。
char str[/url] = "ABCDE";
では、str[0]からstr[5]までの領域がスタック領域に確保されて、"ABCDE"が代入されます。

MNS

Re:char* について

#7

投稿記事 by MNS » 16年前

う~ん、想像以上に難しいことみたいですね。
環境によって異なるから一概には言えないということでしょうか?

というか、そもそも
const char* string = "ABCDE"
char* string = "ABCDE"
前者は定数で後者は変数ですから全く別物ですね

char* string = "ABCDE"
は静的領域に確保されるんですか?
まだ勉強が必要なようです。

これ以上難しいことはわたしは理解できませんので、
質問を絞りたいと思います。
大丈夫そうなんですが、
①char *string = "ABCDE"というコードは安全か
②1が大丈夫な場合、stringは何を指すのか

box

Re:char* について

#8

投稿記事 by box » 16年前

とにかく、コードの断片だけ見ても何ともいえない、
というのは、ご指摘のあったとおりです。

当該の文を含むコード全体と、お使いのコンパイラを
教えてくだされば、より厳密な回答が来ると思います。

Hermit

Re:char* について

#9

投稿記事 by Hermit » 16年前

>const char* string = "ABCDE"
>char* string = "ABCDE"
>前者は定数で後者は変数ですから全く別物ですね

C++ だったら違うかもしれませんが(C++はよく知らないので)
const は、C に於いては、コンパイラに、「ここは書き換えてはいけませんよ」と教えているだけです。
この場合は、"ABCDE" を書き換えてはいけませんと教えているだけです。

char * const string = "ABCDE";
だったら、「string を書き換えてはいけません」という意味になります。
(これくらいはわかるか・・・)

出来上がるコードは、基本的には同じものになります。
(最適化とかが効いて、ちょっと違うコードになることもあるかもしれませんが・・・基本的には同じになります)

で、その部分を書き換えようとした場合・・・エラーになるんでしたっけ?
古い gcc などだと、警告どまりだった気もしますが・・
はっきり覚えてないので、試す気があれば、自分で試してみてください(^^;

見落としていたようなのでついでに
>①char *string = "ABCDE"というコードは安全か
Cを使う限り安全ということはないです。

>②1が大丈夫な場合、stringは何を指すのか
初期状態は、"ABCDE" の 'A' の位置のポインタです。

たかぎ

Re:char* について

#10

投稿記事 by たかぎ » 16年前

> const は、C に於いては、コンパイラに、「ここは書き換えてはいけませんよ」と教えているだけです。

規格上、具体的な規定はありませんが、多くの場合、constの有無によって配置すべきセクションが変わります。
結果として、メモリマップ上のどこに配置されるか、ROMなのかRAMなのかが変わります。
処理系によっては、const修飾子の有無によって、ポインタのサイズが変わります。

> で、その部分を書き換えようとした場合・・・エラーになるんでしたっけ?

未定義動作ですので、完全に処理系によって振る舞いが異なります。

ある処理系では、文字列リテラルがRAMに配置され、普通に書き換えができてしまいます。
ある処理系では、文字列リテラルがROMに配置され、書き込んでも値が変わりません。
ある処理系では、MMUによって保護されるため、書き込もうとするとSIGSEGVが発生するなどします。
ある処理系では、ROMに書き込んだ時点でリセットがかかります。

Hermit

Re:char* について

#11

投稿記事 by Hermit » 16年前

>多くの場合、constの有無によって配置すべきセクションが変わります。

昔ながらの知識だと、間違いが多いか(^^;

const の有無によって、配置する場所が変わるんですか?
auto 変数に const 付けても、auto変数ですよね。
char *string = "ABCDE";
だと、"ABCDE" は、最初から書き換え不能エリアに配置されていいので変化ないはずですよね。
const char string[/url]="ABCDE";
のような場合でしょうか?
外部変数の場合かな・・・

ポインタサイズまで変わるんですか?
strlen には、普通の const でない文字列ポインタは渡せないんですか?
それとも、暗黙に拡張、変換されて渡される?

最近わからないことが多い・・・

toyo

Re:char* について

#12

投稿記事 by toyo » 16年前

>char *string = "ABCDE";
>だと、"ABCDE" は、最初から書き換え不能エリアに配置されていいので変化ないはずですよね。
#include <stdio.h>

int main(void)
{
	char* str = "ABC";
	str[1] = 'Z';
	printf("%s\n", str);
	return 0;
}
コンパイラによっては(具体的にはbcc32)上のプログラムで普通に実行できたりします
bcc32ではconst char* str = "ABC";だと書き換えようとしたところでコンパイルエラーになります
規約に決まってないことはコンパイラ作った人の考え方でいろいろな実装があり限定はできません

たかぎ

Re:char* について

#13

投稿記事 by たかぎ » 16年前

> const の有無によって、配置する場所が変わるんですか?
> auto 変数に const 付けても、auto変数ですよね。

自動記憶域の場合はセクションは変わりません。

> char *string = "ABCDE";
> だと、"ABCDE" は、最初から書き換え不能エリアに配置されていいので変化ないはずですよね。

変化はないですが、書き換え不能エリアかどうかはわかりません。

> const char string[/url]="ABCDE";
> のような場合でしょうか?
> 外部変数の場合かな・・・

静的記憶域の場合は、constの有無でセクションが変わります。

> ポインタサイズまで変わるんですか?
> strlen には、普通の const でない文字列ポインタは渡せないんですか?
> それとも、暗黙に拡張、変換されて渡される?

constの有無でポインタのサイズが変わるのは、例えばM32C用のコンパイラであるNC308です。
この環境では、const T*はデフォルトでfarポインタ、T*はデフォルトでnearポインタになります。
(非標準な独自拡張ではありますが...)
strlenの場合、const char*を受け取りますので、near → farに暗黙的に変換されます。

Hermit

Re:char* について

#14

投稿記事 by Hermit » 16年前

>静的記憶域の場合は、constの有無でセクションが変わります。
そこでしたか。
という事は、extern か、static の場合って事ですね。
そのあたりだと、const の付加で領域が変わっても問題無さそうですね。
そこまで考えてなかった。

>strlenの場合、const char*を受け取りますので、near → farに暗黙的に変換されます。
こんなのも有りですか。不用意に、const は付けられませんね。
これだと、ポインタ配列の確保が難しくなるので、ANSICの仕様にあるなら、
ANSIに文句を言いたい。

hoge

Re:char* について

#15

投稿記事 by hoge » 16年前

>constの有無でポインタのサイズが変わるのは、例えばM32C用のコンパイラであるNC308です。
こんな特殊な例を出しても初心者が混乱するだけでは?
少なくとも規格上は、constの有無でポインタのサイズ変わることはない筈。

たかぎ

Re:char* について

#16

投稿記事 by たかぎ » 16年前

> こんな特殊例な例を出しても初心者が混乱するだけでは?

だから、処理系を補足するように前からお願いしています。
初心者かどうかもわかりませんし。

たかぎ

Re:char* について

#17

投稿記事 by たかぎ » 16年前

> 少なくとも規格上は、constの有無でポインタのサイズ変わることはない筈。

一応これについても書いておきます。
JIS X3010:2003の「6.2.5 型」には、

 voidへのポインタは,文字型へのポインタと同じ表現及び同じ境界調整要求をもたなければならない。同様に,適合する型へのポインタ同士の場合,修飾版であるか又は非修飾版であるかに関わらず,同じ表現及び同じ境界調整要求を持たなければならない。

とありますので、標準規格の範囲では、const修飾子の有無によってポインタのサイズが変わることはありません。

Hermit

Re:char* について

#18

投稿記事 by Hermit » 16年前

>規格上、具体的な規定はありませんが、多くの場合、constの有無によって配置すべきセクションが変わります。
>結果として、メモリマップ上のどこに配置されるか、ROMなのかRAMなのかが変わります。
>処理系によっては、const修飾子の有無によって、ポインタのサイズが変わります。

続けて書いてあったので、ポインタサイズが変わるのも規格上
(ANSI か、ISO か、JIS ですよね。)
規定が無い為かと思ってしまいました。


とりあえず確認で聞きますが、規格上では、
「constの有無によって配置すべきセクションが変わります。 」
の方は、const を付けることによって配置すべきセクションが変わることは許されているんですよね。
(変えない選択肢もあるとは思うが、変える選択肢もあるってことでいいんですよね)

たかぎ

Re:char* について

#19

投稿記事 by たかぎ » 16年前

> 続けて書いてあったので、ポインタサイズが変わるのも規格上
> (ANSI か、ISO か、JIS ですよね。)
> 規定が無い為かと思ってしまいました。

すみません。ちょっと混乱させましたね。

> とりあえず確認で聞きますが、規格上では、
> 「constの有無によって配置すべきセクションが変わります。 」
> の方は、const を付けることによって配置すべきセクションが変わることは許されているんですよね。
> (変えない選択肢もあるとは思うが、変える選択肢もあるってことでいいんですよね)

こちらについては何も決まっていないはずです。
ただ、ほとんどの処理系ではセクションが変わりますね。

Hermit

Re:char* について

#20

投稿記事 by Hermit » 16年前

bcc32 では変わらないようだったので
久しぶりに、gcc 入れてコンパイルすると、
const 部分は、
> .section .rdata,"dr"
が付いてますね。
読み込み専用領域に読み込まれるんでしょうね。

const はこんな作用もあるんだと、改めて知りました。

Justy

Re:char* について

#21

投稿記事 by Justy » 16年前


>読み込み専用領域に読み込まれるんでしょうね

 これ環境によっては結構クリティカルなことになったりするんですよね。

 例えば、1MBのデータを constをつけずに静的変数として定義した場合、
ROM側にその 1MBのデータがあるのはいいのですが、
(実際にも誰も書き換えないのだとしても constが無い以上書き換えられると
判断され)スタートアップ時にその ROM上のデータを RAMにコピーして
データを持つ処理系があったりします。

 メモリがそのデータの容量に対し潤沢にあればいいのですが、
そうでない場合それに気づかないと結構痛いことに……。

たかぎ

Re:char* について

#22

投稿記事 by たかぎ » 16年前

>  メモリがそのデータの容量に対し潤沢にあればいいのですが、
> そうでない場合それに気づかないと結構痛いことに……。

C++だと、動的初期化が必要なオブジェクトは、constを付けていてもRAMに配置されるので、知らないと痛いめにあいますね。

閉鎖

“C言語何でも質問掲示板” へ戻る