• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:組み込み系C言語の学習法)

組み込み系C言語の学習法

OrangeCup150の回答

回答No.6

私はアセンブラはあまり分かりませんが、C言語で変数がどのように番地に割り当てられるかを説明します。ご参考いただければ幸いです。(また、正確かどうか確認していないので間違いがありましたらご容赦ください) 開発環境のウィザードが作成したヘッダファイルで番地と変数名を以下のように対応付けています。 #pragma ADDRESS グローバル変数名 番地 これは変数名と番地を対応付けているだけです。 これにあわせて、通常の変数宣言を行います。 これで、変数名、番地、型情報が結びつけられアクセスできます。 構造体も最終的にはメンバ変数の型でアクセスされます。 #pragma ADDRESS xxx 番地 unsigned char xxx; /* 上の pragma ADDRESS で指定した番地を読み書きする変数 */ #pragma ADDRESS yyy 番地 struct { unsigned char a; unsigned char b; unsigned char c; unsigned char d; } yyy; /* 同様に yyy.a が番地に対応し 番地+1 が yyy.b に対応するメンバ変数になります。 */ yyy は yyy.a とおなじ番地ですが yyy は構造体型のサイズ単位(上記の例では4バイト 構造体型のサイズはコンパイラが自動的に計算を行います)、 yyy.a は unsigned char で1バイト単位に読み書きを行います。 IOをメモリの番地で行うタイプであれば、こんな感じでレジスタの操作ができます。 #pragma ADDRESS はこういう目的のためにグローバル変数のアドレスをコンパイラやリンカに指示するために使われます。通常は、コンパイラとリンカは規則にもとづいて最適なアドレスを割り当てます。(たとえば各変数をぎゅうぎゅう詰めにしてメモリ使用量を最小にするか、アクセス速度の良いアライメントに配置して実行速度を稼ぐなど(メモリ使用量のロスが発生する)) アライメントは、たとえばパソコンなどでは下のように空白をおいて、メンバ変数のアドレスが4の倍数で始まるようにすることです。メモリのバスの都合に合わせて高速化しています。組み込みではあまり関係ないかもしれませんが、相互運用性上、アライメントに使用する倍数は環境依存で問題になることがあります。 struct a{ unsigned char a; /* 0 */ /* unsinged char [3] 分の空白がコンパイラによって置かれる */ unsinged int b; /* 4 */ unsinged int c; /* 8 */ }; ただし、 char 型は例外で詰め物はされません。(実用的な仕様だけど変則的) struct a { unsigned char a; /* 0 */ unsigned char b; /* 1 */ unsigned char c; /* 2 */ unsigned char d; /* 3 */ }; 構造体のビットフィールドを使用してビット単位にアクセスできます。 #pragma ADDRESS zzz 番地 union { struct { unsigned char b7:1; /* メンバ変数名:メンバに割り当てるビット数。1ビットずつ割り振ることでビット番号のビットを個別に操作できる */ unsigned char b6:1; /*略*/ unsigned char b1:1; unsigned char b0:1; } bit; unsigned char byte; } zzz; zzz.bit.b7 = 1; zzz.byte = 0x80; 共用体の zzz は pragma ADDRESS で指定した番地を指し、 共用体中の bit 構造体変数と byte 変数は同じ番地(zzz)に対して異なる方法での読み書きを提供します。 つまり、共用体は同じ番地(zzz)に対して異なる型(bit や byte)でアクセスします。 union COLOR_tag { long color; struct { unsigned char r, g, b, x; } RGB; }; union COLOR_tag dot; dot.color = 0xFF00FF00; dot.RGB.r = 0xFF; dot.RGB.g = 0x00; dot.RGB.b = 0xFF; dot.RGB.x = 0x00; 一般的にはRGBカラー値の操作で上記のような共用体を使うことなどで知られています。(共用体なんて使う人はごくわずかですから共用体を使う人にとっては上記は一般的ですが、実際はそれほど知られていないとおもいます。) 補足 型宣言の構文 union タグ名 { メンバ変数; } 変数名 ; struct タグ名 { メンバ変数; } 変数名 ; 型宣言の後に変数名を書いて変数宣言をいっしょにするとタグ名を省略することができます。 しかし、別のところで変数宣言するときにはタグ名を使用する必要があるので、省略しない方が良いです。 配列は、配列の先頭の要素のアドレス+型のサイズ×インデックスのようにアドレスを自動的に解決していると考えてください。 unsigned char a[10]; int i[10]; a[1] では、 a のアドレス + 1 に対する1バイトの操作ですが、 i[1] は i のアドレス + 2 に対する2バイトの操作です。このように、インデックスに型のサイズ(unsinged char は×1 int は×2)を掛けたアドレスを操作します。 (int 型のサイズは環境によってことなり 2byte か 4byte です) 2次元配列の場合、たとえば int ary [10][3] ; の場合、 ary[0][0] 1000 ary[0][1] 1002 ary[0][2] 1004 ary[1][0] 1006 ary[1][1] 1008 ary[1][2] 100A ary[2][0] 100C ary[2][1] 100E 以下略 のように後ろ側の要素数の配列(内側の配列)からアドレス が割り当てられます。 ary[1][2] は、 ary + (sizeof(int[3]) * 1) + (sizeof(int) * 2) のアドレスになります。( sizeof(型名) または sizeof(変数名) はコンパイラが計算したデータ型のサイズに置換されます ) 関数の宣言で void func_x(int a[][3]) や void func_y(int a[][10][3]) のように一番外側の要素数の指定を省略した宣言ができるのも上記の配列の割り振り規則の効用です。(しかし、10個が3セットと間違って解釈している人も多いです。正しくは、3個が10セットのように右側(内側)から解釈します) ポインタについては簡単に述べると変数の番地を持つ変数です。 int x; int *p; /* ポインタの変数宣言 */ p = &x; /* ポインタの書き込み */ *p = 10; /* ポインタの示す先の書き込み */ ポインタを利用するとポインタの示す番地をポインタの型で読み書きできます。 上記の例では p に x の番地を代入し、 int 型で書き込み(10を代入)を行っています。 構造体の場合、矢印演算子を使ってメンバ変数にアクセスする必要があります。 struct x_tag x, *p; p = &x; p->member = 10; *p.member では通常、正しくアクセスできません。 *(p.member) と解釈されるため。すなわち、 ポインタ変数の番地(&p)+メンバ変数オフセット(構造体の先頭からの位置)の番地に対する操作と解釈される。 (*p).member または p[0].member とすると正しくアクセスできます。ポインタの示す番地+メンバ変数のオフセットと解釈される。 どうみても、言語仕様の欠陥*1です。 (*pointer).member や pointer[0].member 表記が好まれなかったために pointer->member 表記が作られたのでしょう。 p[0] や p[1] は、ポインタの示すアドレス+ポインタのデータ型のサイズ×インデックス、でアクセスするアドレスを解決しています。 すこし、話はそれますが・・・。 int* p, x; int *p, x; 上と下は同じです。 p は int 型のポインタ、 x は int 型の変数です。 つまり int 型は p と x 両方に掛かっているのに、ポインタ宣言は各々の変数名にのみ掛かるという規則です。 両方ポインタにするときには各々の変数名に修飾します。 int *p1, *p2; C言語は変数宣言するときの型の装飾規則が非常にややこしいです。普通に使う分にはさほど難しくないですが、 実際に近い使用例は下記のようになります。 #pragma ADDRESS xxx0 0xXXXXXXXX #pragma ADDRESS xxx1 0xXXXXXXXX #pragma ADDRESS xxx2 0xXXXXXXXX #pragma ADDRESS xxx3 0xXXXXXXXX union xxx { struct {

関連するQ&A

  • 組込みでのC言語勉強法

    はじめまして。 最近、組込みのC言語を勉強しています。 処理速度の面や、可読性の良いプログラム、効率のよいプログラムを書けるようになりたいと思っています。 引数の数はレジスタで処理できる範囲におさめる事や、 構造体を使用するときにはポインタで渡すなど、 コードを書く際に気をつけるポイントがまとまってる書籍やHPなどを知りませんか? もしくは参考にすべき、サンプルコードなど知っていましたら、情報をいただけるとありがたいです。 よろしくお願いします。

  • C言語のGOTO文(組み込み系)

    私は組み込みでソフト開発を行っているものです。 (アセンブラでの経験は長いが、Cは短い) 基本的な質問になってしまいますがご了承ください。 C言語で"goto文は使うな、スパゲティプログラムになりやすい。 使うなら多重ループからの脱出のみ" ということを良く聞きます。 本当ににそうでしょうか?・・・ 例えば、下記サイトの図6をC言語で書いてみました。 もちろんgotoを使いました。 gotoを使わないで、誰でもわかりやすく書くことなどできるのでしょうか? よろしくお願いします。 http://techon.nikkeibp.co.jp/article/NEWS/20071119/142670/?ST=lsi&P=2 /* 開始 */ KAISHI: p74 = High; if(p70 == High){ register = 1; } if(p71 == High){ register = register + 1; if(register != 1){ goto KAISHI; } if(p72 == High){

  • C、C++、Peal、PHPその他「高級言語」といわれる言語について

    僕はPICマイコン(16シリーズ)を趣味で使っており 言語はアセンブラを使っています。 で、質問なんですが最近ホームページを作りたくなり LINUXの勉強も含め自宅サーバーを立ち上げCGIをやってみようと思いました。 で、CGIといえばPealだろと思っていたので、その手の入門書や ネットの情報を見ると冒頭には大抵「大して難しくない」的な事が 書いてありました。 実際にやってみたんですがチンプンカンプンでした。 イメージとしては下記のような感じなんだと思うんですが マイコンのアセンブラと比べたらよっぽど低級言語な気がしてなりません。 アセンブラ=低級言語=人間にわかり難い C、C++等=高級言語=人間に解り易い アセンブラもはじめはチンプンカンプンでしたが、ある程度理解してしまえばそれなりに使いこなせるようになりました。 マイコンのアセンブラは命令数も少ないしイエスかノーだけで「もしも~」とかないので単純といえば単純なんですが・・・ 質問1 高級言語の「人間に判りやすい」っていうのは具体的にどういうことなんでしょうか? 質問2 最近やたらとPHPが流行ってる気がします。 もうPealは廃れてしまったんでしょうか?

    • ベストアンサー
    • Perl
  • C言語が学びやすいおススメの問題集を教えてください。

    C言語を問題を解きながら実践形式で覚えたいと思っています。 今の僕のレベルは、基本的な参考書を1冊読んだ程度で、 基本的な部分や簡単な配列などがどうにかできるくらい。ポインタや構造体などは一応読みましたが きちんと理解して使いこなせるかは疑問・・・といった程度です。 自分で探して目をつけた本としては、柴田望洋の「解きながら学ぶC言語」があります。 この本はどうでしょうか? その他におススメの本はないでしょうか? ぜひ教えてください。

  • C言語

    今、独学でC言語を勉強しているんですが。 大きく、 条件処理、繰り返し処理、配列、関数、2次元配列、文字列、構造体、ファイル処理、乱数、検索、バブル・ソート、ポインタ まではやったんですが(参考書で勉強)。 その次になにを勉強したらよく分からないので、 何を勉強するべきか教えてください。 将来的にこれっと言った作りたいものは決めていません。 お願いします。

  • C言語 よく使うのは?

    C言語の参考書で、例えば1章~8章まであるとすると、 1章~前半くらいは、printfや変数や、演算など出てきると思うんですが、後半にかけて、配列やポインタや関数など出てくると思います。 実際に仕事で、よく使うのを挙げるとどんなのですか?(例えば、ポインタはよく使うや配列もよく使うや) もちろん、変数や演算などが出来ないと条件分岐や配列もポインタも何も出来ないと思うんですが、 上手く言えないんですが、for文はよく使うから、ちゃんと理解していないとダメとか、仕事ではポインタがしょっちゅう使うとか、ありますか? 本屋さんで見ると、ポインタ専用の本や、関数専用の本があるので、よく使うのかなと思いました。 それか、難しく理解が難しいから、より詳しく書かれているんでしょうか? 上手く説明が出来ていないですが、よろしくお願いします。

  • C言語でプログラムを作りたい

    現在、C言語を学習中でして、入出力・制御文・配列・演算子・ポインタ・自作関数・構造体・共用体・ファイル入出力くらいはなんとか使えるくらいになったと思うのですが、そこで、一つ自分でプログラムを作ってみたいと考えています。 しかしながら、これまで学習してきたことを駆使して作れるプログラムが思いつきません。 ですので、なにかいいお題があれば教えていただきたいです。 これまで学習してきたことをしっかりと定着させたいと考えています。 宜しくお願いします。

  • [C言語]変数のアドレスを直接指定する構文

    C言語でのマイコン開発環境に付属しているヘッダーファイルにはレジスタを共用体と構造体でアクセスできるようにしてあります。 アドレスを割り付ける部分の記述は一行ですが、意味を考えた時に構文が複雑すぎて躓いてしまいました。 #define PD (*(volatile struct st_pd *)0xFFFF83A0) /* PD Address*/ 後ろの"*"はst_pdのポインタ型だとして前の"*"はどういう効果になっているのでしょうか? また、複数行に分解して同じ効果を書くこと(例えば変数unsigned long valにアドレス0xFFFF83A0を割り付け)は出来るのでしょうか? 理解を助けるためにお願いします。

  • 組み込みプログラマ

    制御系(マイコン)のプログラマに就職が決まった大学生です。 現在、アセンブラの勉強をしています。 今まで、Z80、PICの経験があります。 しかし、C言語で組み込み系のプログラムを書いたことはありません。 そこで、実際に組み込み系で働いておられる方に質問があります。 1.現在のマイコンではC言語が主流ですか? 2.アセンブラだけでは食っていけませんか? 3.組み込み系は寿命が長いと聞いたことがあるのですが、   本当でしょうか?

  • C言語でゲーム

    今、独学でC言語を勉強しているんですが。 大きく、 条件処理、繰り返し処理、配列、関数、2次元配列、文字列、構造体、ファイル処理、乱数、検索、バブル・ソート、ポインタ を勉強したんですが。 もしも、ゲームを作るとしたら・・ もし、ボンバーマンみたいなのを作るとなるとどういう勉強をすればいいんでしょうか? もうひとつはHALOみたいなxbox関係などはどの様な勉強をすればいいんでしょうか? 質問が多いですが、よろしくお願いします。