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

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

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

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

Q&A

解決済

3回答

3093閲覧

C言語で整数定数のアドレスを変数を介することなく取得することはできませんか?

退会済みユーザー

退会済みユーザー

総合スコア0

C

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

0グッド

0クリップ

投稿2021/10/28 05:45

const char* string = "Hello World\n"; float* p_pi; float pi = 3.14f; p_pi = π //p_pi = &(3.14f);

コメントアウトしたような書き方だと&はビット演算子になるのかエラーとなりダメです。
文字列リテラルの例のように、一度変数を介さないでアドレスを取得する方法はありませんか?

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

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

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

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

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

int32_t

2021/10/28 06:08

どうしてそんなことをしたいのか、に興味がありますね。 配列が引数の関数に定数1個を渡したいとか?
退会済みユーザー

退会済みユーザー

2021/10/28 06:19

可変引数の一般的なマクロ(va_argとか)を使わずに、可変の引数の関数を作りたくて配列を渡したいと思っています。void型のポインタの配列で、あらゆる型の値のアドレスの入る配列です。 それに文字列定数を入れる場合は例のように入れられますが、単なる数値はいちいち変数を個数分宣言してそれを介して入れなければならないのが嫌だなぁと思っています。
退会済みユーザー

退会済みユーザー

2021/10/28 06:38

例えばこんな感じです void* wk[128]; int year, month, day; //printf("%s%d%d%d", "Happy New Year", 2022, 1, 1); wk[0] = "Hello World"; year = 2022; month = 1; day = 1; wk[1] = &year; wk[2] = &month; wk[3] = &day; print_array("%s%d%d%d", wk); //こんな風に定数を直接参照したい、変数の宣言も代入も減らしたい //wk[1] = &2022; //wk[2] = &1; //wk[3] = &1;
jimbe

2021/10/28 07:05

数値は(恐らく、一般的には)アセンブラコードのオペランドとして直接使用されますので、アドレスは存在しないでしょう。 (自己書き換えが出来るような)昔の CPU のアセンブラであればコードのオペランドを参照するコードは書けますが、そのような危険なコードは今は書けないのではないでしょうか。
fana

2021/10/28 07:36

//俺は sizeof(void*) の大きさを信じてるぜ! wk[1] = (void*)2022; //くらえオラァ! とかいうのは,やっちゃいけないことなのかな?
退会済みユーザー

退会済みユーザー

2021/10/28 07:37

Jimbeさん、すみません。よくわかりませんでした。 オペランド「として」というのは、パソコンでいうとHD上の実行ファイルのH定数の部分がメモリではなくCPUのレジスタに読み込まれ、そのレジスタを参照されるのでアドレス指定でアクセスできないという感じですか? H8マイコンを使用しているのですが、ファームを書き込んだフラッシュ領域のどこかにはあるのではないでしょうか?マップファイルを見ると配置されているようなのですが。 知識が足りず頓珍漢なことを言っていたら申し訳ありません。
jimbe

2021/10/28 07:52

H8 やご利用のコンパイラの仕様は分かりませんが、 > 定数の部分がメモリではなくCPUのレジスタに読み込まれ では無く、C をアセンブラコードに変換する際に「" CPU のレジスタに値を設定する命令"の"値"部分として表れる」というようなことです。 >マップファイルを見ると配置されているよう と言われても、お使いの C の仕様でそのマップファイルの情報通りの領域に直接アクセス出来る方法が無ければ、C の標準的な操作・動作しか出来ないでしょうし、マップファイル等は単なる実装形式の一部を覗き見したというだけでしょう。 C の自由度が高いとはいえ、それは当然 C の言語的有効範囲内でですので、人間に見えるモノが全て利用できるとは限りません。
退会済みユーザー

退会済みユーザー

2021/10/28 07:58

Jimbeさん、ありがとうございます。 パソコンでいえばHD上からレジスタに読み込む命令に、H8でいえばフラッシュからレジスタに読み込む命令に置き換えられる。それらにCでアドレス指定でアクセスする方法がないと無理ということですか。 どうにもならなそうですね・・・。
jimbe

2021/10/28 15:43 編集

(angel_p_57さんの回答に気が付かず同じことを書いたので削除)
dodox86

2021/10/29 00:17

興味深い話題ですが、C言語の規格・仕様上での話と、お使いのCコンパイラ、実行環境でできることの可否を分けて考えて結論付ける必要があるかと思います。
Zuishin

2021/10/29 00:48

wk[1] = 2022; wk[2] = 1; wk[3] = 1; とした後、&wk[n] でいいのでは?
退会済みユーザー

退会済みユーザー

2021/10/29 01:54 編集

コメントから察するに、.NETのObject型や、VBのVariant型的な事をしたいんでしょうが、C言語の範疇で似たような事をやろうとすると、普通にコーディングするより逆に面倒になります。 VC++のヘッダでVARIANTの中身見ると、色々な型を詰め込んだ共用体だった記憶があります。
guest

回答3

0

(あまり回答ではないですが他人の回答のコメント欄に返信にするのも不自然なので)

const領域であれどこかに配置されると思うのですが

確かに(コンパイル時に消されないかぎり)リテラルの情報はどこかしらのメモリ(RAM or ROM)に存在するでしょうけれど、それはconst領域のようなデータとしての扱いとは限りません。
機械語のコードの中に取り込まれることがあります。

パソコンでいえばHD上からレジスタに読み込む命令に、H8でいえばフラッシュからレジスタに読み込む命令に置き換えられる。

いいえ、違います。
あなたの言うような「XXという場所からレジスタに読む」命令ではなく、「レジスタにXXという値を書き込む」命令が使われることを言っています。(ここでXXの部分をオペランドと呼びます)

このとき環境によっては、「データはRAMにコードはROMに書かれておりROMから値を読むことはできない」「ROMから値を読めないこともないがRAMから読む時と全く別の複雑な手順が要る」というようなことがありえます。
また、データとしての値ではなく命令の中にオペランドとして含まれている値は、そのまま読める形では存在していないかもしれません。例えば「1020」という値が「255*4^1」として保存されているかもしれません。
これらに対してC言語におけるアドレスを定義することは困難ですので、そのようなことが普通の方法でできるようには作られていないわけです。

投稿2021/10/28 17:09

ikadzuchi

総合スコア3047

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

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

退会済みユーザー

退会済みユーザー

2021/10/29 00:36

回答ありがとうございます。 テキスト領域(プログラム領域)にオペコード+オペランドという形で入っていて、そこにはそのほかの領域のようにアドレスではアクセスできないということでしょうか。 テキスト領域にロードされた内容の大本もHDなりフラッシュなりにあるが、それもメモリではないのでCのアドレス指定では容易にアクセスできない。フラッシュであればフラッシュ書き換えプログラムのようなフラッシュのドライバ経由でリードしなければならない(どこにあるか調べるのも大変) という感じでしょうか。 まだ間違った解釈しているかもしれませんが、本筋ではないのでこのくらいでご容赦ください。
ikadzuchi

2021/11/06 09:23

返信遅くなりすいません。おおむねその理解で問題ないと思います。 細かい話をすると、フラッシュから直接プログラムを実行したりデータを読んだりは可能な場合もあるのに対しハードディスクからは不可能ですが、 更に考えると何が「直接」かという話になり、プログラムからはフラッシュから直接読んでいるように見えてもRAMを経由している場合などあり、本当にRAMを経由していないのかとか、ハードディスクでも仮想メモリとして同様のことをしているなどと考え出すので深く考えないほうがよいです。
guest

0

ベストアンサー

方法はないこともないです。

const char *string = "xxx"; が文字列としての無名のchar配列を使っているように、
float *farray = (float[]){ 1.0, 2.0, 3.0 }; で、無名のfloat配列を使うことができます。
これは C99 で追加された複合リテラルです。
※なお定数ではありません。あくまで無名で書き換え可能な配列です。

そしてCでは、ポインタを経由してアクセスする限り、float型の変数と1要素のfloat配列の扱いは変わりません。
ということで、
const float *p_pi = (float[]){ 3.14 };
とすれば、( 実体は書き換え可能なんですが ) 無名の定数のポインタを取得したように見えます。

…まあ、ここまでする意味があるか? と言われると分かりませんが。

なお、複合リテラルを実際に用いるなら、その特性には注意をしておいた方が良いと思います。
参考: https://www.jpcert.or.jp/sc-rules/c-dcl21-c.html

投稿2021/10/28 10:42

angel_p_57

総合スコア1681

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

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

thkana

2021/10/28 22:35

質問者さんはH8をターゲットとしている様子。日立のコンパイラベースだとC99には対応していない可能性も結構ありますね。
退会済みユーザー

退会済みユーザー

2021/10/29 00:19

回答ありがとうございます! wandboxで動作確認できました。 残念ながらthkanaさんのおっしゃる通り、開発したい環境では非対応でした。 今後利用していきたいと思います。
guest

0

方法は無いです。

単項 & のオペランドは左辺値 (lvalue) であることを言語仕様は要求しており、整数リテラルはそれにあてはまりません。 生成される機械語の実態としてもメモリに配置されない (即値としてやりとりされる) のが普通です。

投稿2021/10/28 06:03

SaitoAtsushi

総合スコア5684

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

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

退会済みユーザー

退会済みユーザー

2021/10/28 06:08

const領域であれどこかに配置されると思うのですが、方法はないんですか・・・
jimbe

2021/10/28 07:06

「どこかに配置され」ない、ということです。
SaitoAtsushi

2021/10/28 15:24

機械語の話を持ち出したのは良くなかったです。 レイヤの違う話を混同してしまうので説明に使うべきではありませんでした。 まずは言語の理屈として「どこかに入っている値」と「評価することによって得られた値そのもの」が区別されていて、それが左辺値 (lvalue) と右辺値 (rvalue) です。 右辺値は仕様では「式の値」という言い方のほうがよく使われています。 (左辺値は文脈によって右辺値に変換されることもあります。) 値そのものは場所と結びついておらず、場所がないのでアドレスも得られないということです。 たとえば &(pi+1.0) とした場合、これは実際の C ではエラーになりますが、アドレスを得られるとしたらどのようなアドレスが得られるべきだと考えますか? このとき計算結果の値の寿命はいつでしょう ? 数値リテラルもそのような一時的な値を作り出すなんらかの存在であるにすぎず、メモリ上に配置されてから取り出されているとは考えないでください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問