C言語超初心者の質問:ltoa関数の意味がわからない

このQ&Aのポイント
  • C言語の勉強中の超初心者が、PICマイコンのAD変換のプログラムで使われているltoa関数の意味がわからないという質問です。
  • 特に、「ltoa(*のアスタリスクの意味」「((WORD*)の意味(アスタリスクの意味)」「(&ADRESL))の意味」「,ANString);の意味」について、分かりやすく解説してほしいとのこと。
  • ネットでの検索でも確かな解答が得られず困っているため、誰でもわかるように解説をしてほしいとの要望もあります。
回答を見る
  • ベストアンサー

C言語の超初心者です。質問があります。

C言語の勉強中の超初心者です。 PICマイコンのAD変換のプログラムの中に下記の表記があります。 ある本に書いてあるものですが、全く意味がわかりません。 どなたか解説をお願いします。 static char ANString[8] ・ ・ 途中を省略 ・ ltoa(*((WORD*)(&ADRESL)),ANString); プログラムのコメントには「ASCIIに変換」とあり、アスキー文字に変換することは何となくわかりますが、 ltoa(*((WORD*)(&ADRESL)),ANString); の意味がわかりません。 よろしければ小学生でも理解できるよう、下記のようにくだいてご説明をお願いします。 ltoa(* のアスタリスクの意味 ((WORD*) の意味(アスタリスクの意味) (&ADRESL)) の意味 ,ANString); の意味 ネットで調べましたが、表記が個々に違っていて理解できません。 このような質問の内容でよいのか判断もつきませんが、ヨロシクお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.1

超初心者とのことですが、次の用語は理解できてますか? ・ポインタ、アドレス ・型とキャスト(型変換) ・関数と引数 ・文字列 &ADRESL ADRESLのアドレス。 ADRESLの型が書いてないのでわからないが、 その型へのポインタになる。 (WORD *) キャストで、「ADRESLの型へのポインタ」を「WORD型へのポインタ, WORD *型」に変換。 * 単項の*は、ポインタが示す実体を参照するもの。 ((WORD*)(&ADRESL)) が WORD へのポインタなので、そのポインタが示すアドレスにあるWORD型のデータを参照する。 全体での意味は itoa 関数に 第1引数: *((WORD *)(&ADRESL)) 第2引数: ANString を指定したもの。 itoaがどんな動作をする関数なのかは、マニュアルを読むこと。 おそらく、char ADRESL[] みたいになっていて、 ADRESL[0]とADRESL[1]の8bit+8bitを、16bitのデータ(WORD型)と見做して、atoiで処理する、ということではないかと予想します。

mugaku_ou
質問者

お礼

早速のご回答ありがとうございます。 下記の件ですが・・・ ・ポインタ、アドレス ・・・ポインタは変数が格納されたアドレスを記憶する変数と理解しておりま               す。 ・型とキャスト(型変換)・・・基本的な型は本を見ればわかりますが、PICの本には「WORD」という型は記載がありません。 キャストは変数の型の変換に使用すると理解しており、下記のようにポインタの型の変換ができるとは知りませんでした。ポインタの型ということは、「そのアドレスに格納されたものの型ということでしょうか?」 WORD型について調べましたが、intと書かれたり、unsigned short 型と書かれたり、まちまちなんですが実際にはどれが正解なんでしょうか? (WORD *) キャストで、「ADRESLの型へのポインタ」を「WORD型へのポインタ, WORD *型」に変換                ・関数と引数・・・関数と引数は何となくですが、ある程度理解できます。少なくとも下記については理解できます。 itoa関数とありますが質問ではltoa関数ですが、両方共同じような関数で、数値を文字列に変換する関数と理解していますが、itoaはint用でltoaはlong用と思っていますが、このように理解してよろしいでしょうか? 全体での意味は itoa 関数に 第1引数: *((WORD *)(&ADRESL)) 第2引数: ANString を指定したもの。 itoaがどんな動作をする関数なのかは、マニュアルを読むこと。 ・文字列・・・何となく理解できます。 最終的な解説内容についてですが、説明不足で申し訳ございません。 ある程度、詳しく説明しますとPICに関しても初心者なのでよく理解していませんが、PICマイコンで温度センサーのアナログ信号をAD変換した時のデータの格納先がPICで言う「ADRESLレジスタ」で変換結果のデータは10bitの電圧データとのことです。このデータをVBで作成したプログラムで温度として表示するというもので、実際の温度が611とかあり得ない温度の数値になっており、これを正常な温度数値とするためにスケール変換という作業が必要なのですが、最終的なPIC側の結果(ANString変数)にスケール変換用の式(ANString = (ANString * 50) /1024;)を書き込みコンパイルしましたが、これまた5とかあり得ない数値になってなっています。 わからないながら考えましたが、ASCIIに変換した後にスケール変換ができないのではないか? 文字列を計算することはできない? と思い、当質問文の前にスケール変換する式が必要になると考えました。 それには当質問文を理解しないとできないと思い質問させていただきました。 また、ADRESLの詳細としては(これもまた、理解に苦しんでしますが・・・) 実際の結果は ADRESH(8ビット) と ADRESL(8ビット)に10ビットで格納されるようです。 イメージとしては  |ADRESH |ADRESL  |              0000111111111111 となっていて、1111111111の部分が実際の格納データで、二つに跨いで格納しているようです。正直わけがわかりません。 本の内容は理解できませんが、当質問文の内容で最終的に「ANString配列変数」に本データがASCIIに変換されて代入されるようです。 正直、ネットで調べてもPICのC言語とは趣が違い、調べれば調べるほど理解に苦しみます。 もう少し、いろいろ調べて勉強します。 ありがとうございました。

その他の回答 (2)

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.3

・WORD型 C言語では、typedefを使って、既存の型に別名を付けることができます。 また、マクロを使って、コンパイル前に置換することができます。 たしかに、WORDという型は、C標準にはありません。 なので、ヘッダ等のどこかでtypedefまたは#defineでWORDを定義しているはずです。 1ワードと言うと符号無し16bitを指すケースが多いです。 16bitのunsignedの整数がどの型になるかは、コンパイラや対象次第で決まりはありません。 なので、int型が16bitの環境ではunsigned int, shortが16bitの環境では unsigned short がWORDとして定義されていたりします。記述がバラバラなのはこのためです。 実際に何なのかは、#includeで取り込むヘッダファイルのどこかにtypedefや#defineでWORDが定義されているはずなので、確認してください。 ・ポインタの型 「そのアドレスに格納されたものの型ということでしょうか?」 はい、そうです。 ・二つに跨いで格納 よくある実装です。 場合によって、2つの8bitのレジスタとして別々に利用したり、つなげて1つの16bitのレジスタとして利用したりします 追加された情報からすると。 メモリ上では ADRESL ADRESH の順番に並んでいます。これはリトルエンディアンと呼ばれるものです。 &ADRESL は、ADRESLのアドレスですが、そのまま *で実体にアクセスすると、ADRESLの8bitしかアクセスできません。 そこで、このポインタをWORD *型に変換することで、ADRESH ADRESLを組み合わせた16bitのWORD 型へのポインタにします。 * でそのWORD型にアクセスするので、 16bit(実際には、そのうちの10bitにしかデータは入っていませんが)の値としてアクセスできるようになります。 その16bitの数値を、ltoaで文字列にします。元が611なら、ANStringは"611"です。 これは ANString[0] = '6' ; ANString[1] = '1' ; ANString[2] = '1' ; ANString[3] = '\0' ; になります。 この中で、PICマイコン独自なのは、「ADRESL, ADRESH レジスタの関係」だけです。 それ以外はPCでも使われるテクニックです。

mugaku_ou
質問者

お礼

またまた、早速のご回答ありがとうございます。 先ほどのお礼回答後に本を見て見ましたが、正しくご回答の通りと思います。 (今回のご回答も難しい言葉が出てきますが、何となくですがこの通りだとわかりました。) まだ、PICに関してもC言語も本を見て1週間くらいですので、確かに理解しておりませんでした。 ポインタに関しての型に関しても頭がパニックになりますが、ちゃんと記載がありました。 厚かましいようですが、応用が利く段階ではないのでできればご教示お願いします。 今やりたいことはADRESLの中身をスケール変換した後にltoa関数で文字列変換ができれば正しくANString配列変数へ文字が代入されると思います。 どのようにしたら、中身を(ADRESL * 50) /1024;の値にできるでしょうか? 自分なりに考えたんですが、配列変数の場合にはANString = (ANString * 50) /1024;のようにすると配列先頭の'6'かと思いましたが、(6*50)/1024=0.2929… となるので、中身ではなく、配列の先頭アドレスの値が計算対象になっているのではないでしょうか?  実際のVBソフトでの表示は5になっていますので、6ならば0.2929でも合わないし、611であれば29.83…となり、これは温度として正しい値となります。 したがって、どちらも5とはかけ離れているので色々考えてANStringはアドレスの値ではないか?と思った次第です。 間違っているでしょうけど・・・ もう一つ、最終的にANStringに代入された値(ご回答いただいた下記の内容)をスケール変換できないのでしょうか?  ANString[0] = '6' ; ANString[1] = '1' ; ANString[2] = '1' ; ANString[3] = '\0' ; 最終的には (611*50)/1024=29.83 の29.8の値が、できるのかわかりませんが下記のようになればと思っております。 ANString[0] = '2' ; ANString[1] = '9' ; ANString[2] = '.' ; ANString[3] = '8' ; ANString[4] = '\0' ; 小数点は使えるのでしょうか? これも基本的なことなのでしょうが・・・ 文字列であれば問題無い? ど素人のたわごとにお付き合いいただきまして誠に恐縮ですが、ご教示をお願い申し上げます。 本来であればもう少し勉強してお伺いしなくてはならないことは、十分わかっております。 ありがとうございます。

  • LHS07
  • ベストアンサー率22% (510/2221)
回答No.2

*はポインターのことです。 基礎の基礎がまだ理解していないようですので、地平線から太陽が見え始めるようになりまで教科書をひたすら読みましょう。 今が一番辛いときですが読み続ければかならずわかってきます。楽しくなってきます。

関連するQ&A

  • c言語でintをchar*に代入

    c言語を用いてマイコンにシリアル通信経由で値を書き込もうとしています. PCからAscii(Aの場合は0x41)でマイコンにデータを送信し,マイコンで static int receivedUART[30]; 上記の変数に格納後し,書き込みのコマンドだと判断した場合に, char *kWifiSsid の変数に書き込みたいと考えています. 以下の関数を作成しました。 void setSSID(int *k){ char ssid[30] = {0}; for(int i = 0;i < SSID_LENGTH;i++){ char t; if(*k == 10){ Serial.println("brek"); break; } t = (char)*k; //最初のに2要素はコマンドのため無視 if((i != 0) && ( i != 1)){ ssid[i-2] = t; } ++k; } kWifiPass = ssid; } 上記の関数の引数にはreceivedUARTを指定しています. しかし,上記ではうまくkWifiPassが書き換えられませんでした. どのように改良すればintの値をchar*に書き込めますでしょうか?

  • C++のクラス内のchar *strについて

    初歩的な質問で申し訳ありませんが、いまC++を勉強していてわからないところがあったので質問させていただきます。以前C言語を少ししていたのでアスタリスクがポインタのことを指しているというのはわかるのですがC++でクラスを扱うとなったときなぜクラス内でconst char *strと変数の前にアスタリスクがつくのかがわかりません。ためしにアスタリスクを外してコンパイルすると4つくらいエラーが出てきて読み取り専用メンバへの代入とかchar* から char への不正(?)な変換とか出てくるのですが肝心のアスタリスクをつける意味が結局わかりませんでした。なので誰か教えてください。

  • 2進数からアスキーコードへの変換についって

    趣味で電子工作を行っているものです。 picマイコンを使用して、A/D変換の結果10bitのデータを得ました。 8ビットのマイコンなので2つのレジスタに分かれてデータが格納されています。(上位2ビットと下位8ビット) この2進数のデータを10進数に変換し、一桁ごとにアスキーコードにして、シリアル通信を用いてPCに送りたいと思っています。 ここで、10bitのデータの2進数から10進数への変換。 10進数のデータを一桁ずつアスキーコードへ変換。 の2つのやり方がわかりません。 2進数のデータのままPCに送り、PCのソフト側で変換するほうが簡単なのですが、今回はPIC側で変換し、アスキーコードで送る必要があります。 プログラムに使用する言語はアセンブリです。 どなたか分かる方がいましたら教えてください。

  • c言語でint配列をdoubleに変換

    c言語でマイコンプログラムを作成しています. int型の配列をdoubleに変換するために以下のプログラムを記述し,テストしました. int a[4] = {0,0,1,8}; char s[4]; double d; char *temp; sprintf(s,"%d%d%d%d",a[0],a[1],a[2],a[3]); //文字列charをdoubleに変換 d = strtod(s,&temp); 望む結果は 18 ですが,なぜか上記結果は 1800 となりました. 試しに int a[4] = {1,2,3,4}; と,1234と表示されました. 上記より,出力値が左詰めのようになっています. 試しにVisual Studio 2013 C++で同様のプログラムを実行すると,所望の結果を得ることが出来ました. プログラムがおかしいのでしょうか?それともマイコンのコンパイラのバグでしょうか? お分かりになられる方がいらっしゃいましたら,ご教授宜しくお願い致します.

  • C言語のプログラミング

    C言語のプログラムを読もうとしているのですが、初心者故に難儀しており、お助けいただければ幸いです。 プログラムの内に下記のような「CnsktModule* 」の部分があります。 例えば、char *p; のような記述であれば、p はポインタでポインタの指し示す内容はキャラクタの型を 持っていると理解できるのですが、「CnsktModule* 」はどのように解釈したらよいのでしょうか? CnsktModule* cnsktNew(char *printer, char *locale, char *folder_path, int port_num) { 以下省略

  • C言語

    (a) キーボードから入力された文字列をそのままディスプレイに表示するプログラムを作成しなさい。 という問題 #include<stdio.h> main() { char word[1000]; /*文字型の変数の宣言*/ scanf("%s", word); /*キーボードから文字列を入力*/ printf("%s\n", word); /*入力した文字列を出力*/ } と作りましたがこれではコンソール中で文字を打ってからエンターを押さないといけないからといわれ再提出になってしまいました。 エンターを押さないでそのまま出力するということは、できるのでしょうか? あと自分の作ったプログラムではスペースや改行を使うことができないから使えるようにしろと言われてましたがそれわできますか? 変換仕様をかえればいいのですか ほかにもかえる所はありますか?

  • PICのプログラムについて質問です

    使用するPICは16F84Aで、MPLAB IDEv8.88を使ってこのようなプログラムを作りました。 #include"pic.h" static void pic_init(); static void Delay_ms(unsigned char ms); static void Delay_1ms(); void main(){ pic_init(); while(1) { RB0 = 1 ; Delay_ms(250); Delay_ms(250); Delay_ms(250); RB0 = 0 ; Delay_ms(250); Delay_ms(250); Delay_ms(250); } static void pic_init() { // GPIO = 0b00000000; TRISA = 0xFF ; TRISB = 0x00 } static void Delay_ms(unsigned char ms) { unsigned char c; for (c=ms ; c>0 ; c--) { Delay_1ms(); } } static void Delay_1ms() { unsigned int cnt; unsigned int i; cnt = 76; for (i=0 ; i<cnt ; i++) { NOP(); } } ポートB0の出力を0から1にするプログラムなのですが、実行すると Error [314] C:\Users\moriwaki\Desktop\PIC program\step_test2.c; 52.24 ";" expected Error [254] C:\Users\moriwaki\Desktop\PIC program\step_test2.c; 77.0 undefined variable: "pic_init" ********** Build failed! ********** というエラーが出ます。このようなエラーが出る原因を教えて頂けないでしょうか。お願いします。

  • PICマイコンをアセンブラでAD変換をした時に、、

    現在PICマイコンの16f88を用いてアセンブラでAD変換の勉強をしています。とりあえずいろいろなサイトやデータシートを見てAD変換した結果をPORTBに出力させるテスト用のプログラムを完成させたのですが、AD変換の結果を格納するADRESLのデータをうまく読み込むことができませんでした。その時のプログラムは(結果は左詰め,X_Lは自分で定義した変数) BSF STATUS,RP0 MOVF ADRESL,W MOVWF X_L ;ADRESLの結果をX_Lに保存 BCF STATUS,RP0 MOVF X_L,W MOVWF PORTB こんな感じです。わざわざADRESLの結果をX_Lに保存しなくても直接出力することもできるんですが気にしないで下さい。で、このプログラムだとPORTBにつないだ全てのLEDが点灯します。 ところがプログラムを以下の様に書き変えたら見事にADRESLレジスタの中身が出力できました。何が起きたのでしょうか?バンクの切り替えの前にWレジスタをX_Lレジスタに書き込むのと、バンクを切り替えてからWレジスタをX_Lレジスタに書き込むのとでは結果が同じになると思うのですが、、、。 BSF STATUS,RP0 MOVF ADRESL,W BCF STATUS,RP0 MOVWF X_L MOVF X_L,W MOVWF PORTB

  • なぜかビープ音が鳴ります(C言語)

    下記のプログラムはCHAR_SETの値に応じてASCII文字セットと拡張文字セットのどちらかを表示するようにコンパイルするものです。 #include <stdio.h> /* CHAR_SETを256または128のいずれかの値に定義する */ #define CHAR_SET 256 int main(void) { int i; #if CHAR_SET == 256 printf("すべてのASCII文字セットと拡張子を表示する\n"); #else printf("ASCII文字セットのみを表示する\n"); #endif for(i=0; i<CHAR_SET; i++) printf("%c", i); return 0; } 【質問】 このプログラムを実行するとビープ音が鳴るのですが、それはなぜでしょうか? いろいろ試して分かっていることは、CHAR_SETを512にすると2回鳴ることです。 ちなみに、「VisualC++.net Standard Version 2003」でコンパイルしました。 この問題に知識のある方、回答をお願い致します。

  • 数値をASCII文字にする方法についての質問です。

    数値をASCII文字にする方法についての質問です。 PICマイコンのプログラミングをするために、C言語を使用しています。LCDに数値を表示するには変数を数値ではなく文字で渡してやらないといけないようなのですが、その変換のしかたがわからず調べていると、あるサイトで二桁の数字(suuji)の1の位をASCII文字(hensu)にするために、 hensu = (suuji % 10) + '0'; のようにコードを記載していました。実際にこの通りプログラミングしてみるとLCDに表示されたのですが、なぜこのようにするとASCII文字に変換できるのかがわかりません。('0'を加えるとアスキー文字になるのでしょうか?)どなたか教えて頂ければと思います。