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

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

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

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

組み込み開発

組み込み開発とは、スマートフォンや家電、自動車などに組み込まれているコンピューターシステムの開発のことです。特定の用途に特化しており、限られた機能のための開発を指します。組み込み開発で作られた機器を組み込み機器と呼び、近年ではPCのオペレーションシステム(OS)にも採用されています。

ポインタ

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

マイコン

マイクロコンピュータの略で、CPUにマイクロプロセッサを用いたコンピュータのこと。家電製品、電磁機器などの制御に用いられています。単体でコンピュータとしての機能を一通り備えています。 現代のパーソナルコンピュータに近く、同時期のメインフレームやミニコンピュータと比べ、小さいことが特徴です。

Q&A

解決済

3回答

858閲覧

ポインタ変数の表記について

Nyanmage.neko

総合スコア7

C

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

組み込み開発

組み込み開発とは、スマートフォンや家電、自動車などに組み込まれているコンピューターシステムの開発のことです。特定の用途に特化しており、限られた機能のための開発を指します。組み込み開発で作られた機器を組み込み機器と呼び、近年ではPCのオペレーションシステム(OS)にも採用されています。

ポインタ

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

マイコン

マイクロコンピュータの略で、CPUにマイクロプロセッサを用いたコンピュータのこと。家電製品、電磁機器などの制御に用いられています。単体でコンピュータとしての機能を一通り備えています。 現代のパーソナルコンピュータに近く、同時期のメインフレームやミニコンピュータと比べ、小さいことが特徴です。

0グッド

0クリップ

投稿2023/09/27 00:37

編集2023/09/27 08:05

実現したいこと

ポインタ変数の変数宣言や表記方法への知見を広げたい。

前提

現在RX64Mマイコンを使用し、e2studioにてプログラムを書いています。
メーカーが出しているAPIリファレンス内でのポインタ変数の表記が見たことないをしていたため、
どういったものなのか知りたい。

表記について

下記に実際のソースコードではないですが、使用されている変数などについてまとめます。

C

1typedef unsigned char uint8_t 2 3volatile uint8_t g_sci0_tx_buf; 4 5g_sci0_tx_buf = 'A'; 6 7R_Config_SCI0_Serial_Send((uint8_t *)&g_sci0_tx_buf, 1U); 8 9//Renesasの関数の資料にはこのように書かれています。 10MD_STATUS R_<Config_SCI0>_Serial_Send ( uint8_t * const tx_buf, uint16_t tx_num ); 11

疑問点

R_Config_SCI0_Serial_Sendと書かれた関数の引数として、

(uint8_t *)&g_sci0_tx_buf

が渡されていますが、 * と & を同時に使用すると、
①ポインタ参照先のデータ型が「uint8_t
②データ型をポインタ型にする「*
g_sci0_tx_bufをアドレス演算子にする「&

なので、g_sci0_tx_bufが存在している番地の番地?になってしまうのではと思いました。
この記法の意味とメリットを知りたいです。

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

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

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

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

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

int32_t

2023/09/27 00:46

疑問点のところ、* が欠落しているように見えます。欠落しないように修正お願いします。
otn

2023/09/27 01:10

↑文中のコードはバッククォート ` で前後を囲まないと、マークダウン書式を見なされます。 * だと斜体文字になるとか。 `"*"` のように書きましょう。
jimbe

2023/09/27 04:17

示したいのは * とか & で、 "" で囲むのはそれらを装飾するためですので、 "" の代わりに `` で囲むというほうが良さそうに見えます。
guest

回答3

0

ベストアンサー

(uint8_t *) はキャストであり、このときの *uint8_t * という型を表す表記の一部です。 間接演算子である * ではないです。

volatile uint8_t 型の g_sci0_tx_buf& を適用することで volatile uint8_t* 型の値が得られ、それをキャスト演算子 (uint8_t *) を適用することで uint8_t * に変換するというのがこの式の意味です。

キャストは型変換の指示ですが、変換結果が言語仕様として規定されている場合とされていない場合があります。 ポインタが指す型の型修飾子 (const, volatile, restrict のこと) は追加する方向に変換してもよいですが、剥がす方向に変換した結果は規定されていません。

つまり volatile uint8_t*uint8_t * に変換するというのは言語仕様では未定義なので何が起こるかわかりません。

R_Config_SCI0_Serial_Send の中では volatile の性質を考慮せずに動作するということなので割込みや並列処理がかかわると破綻するかもしれません。 逆に言えば volatile の性質と無関係な処理しかしていないのであれば問題はないのかもしれません。 それはコンパイラや実行環境の性質次第 (言語仕様では挙動が規定されない) なのでそれを把握して正しく使うのはプログラマの責任です。

投稿2023/09/27 01:54

SaitoAtsushi

総合スコア5446

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

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

Nyanmage.neko

2023/09/27 02:14

ご回答ありがとうございます。型変換を行っているという事がこの式の本当の意味なのですね。 型修飾子をはがす方向に変換した結果は規定されていないという事を考えると、 `(uint8_t *)&g_sci0_tx_buf` は、 `&g_sci0_tx_buf` として使用するほうがよさそうですね。 注意してプログラムしたいと思います。
fana

2023/09/27 05:04 編集

R_Config_SCI0_Serial_Send() 関数の引数の型が `uint8_t*` であるとしたら,`&g_sci0_tx_buf` とだけ書くのではコンパイルが通らないのではないでしょうか. (暗黙的に型変換できないなら「volatile uint8_t* から uint8_t* への変換ができない」というエラーになる) なので,ここでは明示的なキャストが要る,ということなのかな,と推測します.
Nyanmage.neko

2023/09/27 08:03

API資料の中での引数は、「uint8_t* const tx_buf」と表記されていました。 こうなると、(uint8_t*)&_sci0_tx_buf の方が正しいという事になるのでしょうか。
otn

2023/09/27 11:36 編集

> こうなると、(uint8_t*)&_sci0_tx_buf の方が正しいという事になるのでしょうか。 そのマイコンのメーカーが出しているリファレンスにそう書いてあるのなら、それが正しいです。 CのJIS規格では、「volatile修飾型で定義されたオブジェクトを非volatile修飾型の左辺値を使って参照しようとした場合,その動作は未定義とする」と書かれており、volatile無しのポインターにキャストした後、キャスト後のポインターを使ってアクセスする時の動作は未定義なので、ある処理系では上手く動いていても、「他の処理系でも動かすかもしれないプログラム」を書くのならばだめです。 しかし、マイコン用のプログラムということは、「どの処理系でも動くプログラム」を書くつもりはないと思うので、「言語規格でどうなのか?」よりも、「その処理系でどうなのか?」が確認できていれば十分です。 ただ、ドキュメントに「どうなるか」が書いてあるかどうか。処理系定義動作と異なり、未定義動作となっているものがその処理系でどうなるのかは必ずしも書いてないので、その場合は結果については不明で、安心して使えないことになります(処理系定義動作は処理系作成者がどうするか決めて文書化することが規格で求められている)。 ということで、ドキュメントにサンプルが載ってるならその通りにする。
Nyanmage.neko

2023/10/01 23:42

otn様回答ありがとうございます。 >「言語規格でどうなのか?」よりも、「その処理系でどうなのか?」 このあたりを意識しようと思います。この場合はドキュメント通りが一番ですね。しかし、Cの規格も理解していなければいけないということで、今回とても勉強になりました。
guest

0

*&を同じ式内に書いていても内側から順番に見ていくだけです。

(uint8_t *)&g_sci0_tx_buf

g_sci0_tx_bufuint8_t
&g_sci0_tx_bufuint8_t 型のアドレス
(uint8_t *)&g_sci0_tx_bufuint8_t 型のアドレスをuint8_t 型のアドレス として見るよう指示(キャスト)

(volatile の影響を無視するとすれば) ③ は(結局)無意味なので表記としては ② の状態でも構わないでしょう。

投稿2023/09/27 04:26

編集2023/09/27 04:30
jimbe

総合スコア12648

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

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

Nyanmage.neko

2023/09/27 04:31

ご回答ありがとうございます。 見るべきところの順番が書いてあるので大変分かりやすいです。 結局は②であることを、Renesasがユーザーズマニュアルを作成する際に③としてみるように強調したいがための記述なのかもしれません。いずれにせよこういう表記の仕方もあるという事が勉強になりました。
guest

0

g_sci0_tx_buf というのは、uint8_t 型の変数です
R_Config_SCI0_Serial_Send関数の第一引数は、送信データ列が格納されているバッファの(配列?)の先頭アドレスを取るようになってます

ってことで、

なので、g_sci0_tx_bufが存在している番地の番地?になってしまうのではと思いました。

これで正解です

(uint8_t *)&g_sci0_tx_buf

で、&でその変数のアドレスを出してるのに、(uint8_t *)でキャストしてるってのは余計なお世話です、が、まあ、パッと見てわかりやすくするために、わざわざキャストしてるのでしょう。

投稿2023/09/27 00:47

y_waiwai

総合スコア87778

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

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

Nyanmage.neko

2023/09/27 01:24

ご回答ありがとうございます。つまりは、 (uint8_t *)&g_sci0_tx_buf は、 &g_sci0_tx_buf と記述するのと同じという事でしょうか。
fana

2023/09/27 01:30 編集

個人的には > 番地の番地 という言葉が「正解」とは思えないです. (単にシンプルに「番地」と言うことになるのでは.)
y_waiwai

2023/09/27 04:35

> (uint8_t *)&g_sci0_tx_buf は、 &g_sci0_tx_buf と記述するのと同じという事でしょうか。 そのとおりです キャスト、ってのは型を変換する、ものではなく、型を読み替えるだけ、なのに注意しましょう。 > 番地の番地 ではないですね。あくまでg_sci0_tx_buf の番地、です &g_sci0_tx_buf とすることで、uint8_t* 型となります。 フォローありがとうございます >fanaさん
Nyanmage.neko

2023/09/27 04:44

お返信ありがとうございます。fana様も補足ありがとうございます。 あくまでも「番地」と理解致します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問