アプリ版:「スタンプのみでお礼する」機能のリリースについて

(1)以前GPSで取得した測位データをRS232C通信でPCに表示するプログラムを作成するに当たって、多くの方に助言を頂けたことでなんとかNMEAデータを表示できるようになりました。
(2)そこで次の段階として、取得したNMEAデータに含まれる”緯度””経度””時刻”の要素のみ取り出して表示する方法として、strtok関数を用いたプログラムを教わり、用意した文章から必要な要素のみを出力する方法も確認できました。
(1)と(2)のプログラムをあわせて、受信したデータから緯度経度時刻のみを表示するプログラムを作成したいのですが、
assignment makes pointer from integer without
とコンパイル時に表示されてしまいます。ポインタの受け渡しに問題があるということでしょうか?どのように組み合わせれば受信データから必要なデータを表示できるようになるでしょうか。方法があればご教授お願いします。
以下が(1)と(2)のプログラムです。
(1)受信したデータをRS232C通信でPCに指定した行数表示するプログラム
#include<unistd.h>
#include<fcntl.h>
#include<strings.h>
#include<termios.h>
#include<stdio.h>

#define BAUDRATE B4800
#define MODEMDEVICE "/dev/ttyS0"

int main()
{
int fd, c, res;
int i=0;
int j=0;
struct termios oldtio, newtio;
unsigned char buf[512];

if((fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY ))==-1){
perror(MODEMDEVICE);
exit(-1);
}

tcgetattr(fd, &oldtio); /*シリアルポートの設定を待避*/
bzero(&newtio, sizeof(newtio)); /*新しいポートの設定の構造体をクリア*/
newtio.c_cflag = (BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD);/*ボー:4800*/
newtio.c_iflag = (IGNPAR | ICRNL);
newtio.c_oflag = 0;
newtio.c_lflag = ICANON;
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);

while (i==0) {

res = read(fd,buf,512);
buf[--res]=0; j++;
printf("%s\n",buf);
//j++;
if(j==48)i++;/*NMEAセンテンス1セットは24行(12種と1行ずつのスペース)なのでここでは48行で2セット分のループ*/
}
tcsetattr(fd, TCSANOW, &oldtio);
close(fd);
return(0);
}
(1)実行結果
$GPRMC,081312,A,3428.9433,N,13549.4905,E,0.0,0.0,060808,6.7,W,A*06

$GPRMB,A,,,,,,,,,,,,A,A*

$GPGSA,A,3,03,06,07,,16,,21,,25,27,,,2.3,2.0,1.0*34
・・と48行このようなNMEAセンテンスを表示します。

(2)NMEAセンテンスから時刻、緯度、経度のみを出力
#include <stdio.h>
#include <string.h>
#include <math.h>

char buf[512]="$GPRMC,143514,A,3428.9468,N,13549.4507,E,0.0,196.2,180708,6.7,W,A*05"; /*緯度経度時刻がすべて含まれているGPRMCからデータを取得したいのでGPRMCのモデルを1行用意*/

void pnmea(void) {
int utc;
double lat; /*緯*/
double lon; /*経*/
char ew; /*東西*/
char ns; /*南北*/
char stat;
char *p;
/*一行のNMEAセンテンスから時刻緯度経度のみを取り出すために、strtokで”,”ごとのトークンを得る*/
if ((p=strtok(buf,","))==NULL) return;
if (strcmp(p,"$GPRMC")!=0) return; /*センテンスの先頭は$GPRMCか?*/
if ((p=strtok(NULL,","))==NULL) return;
sscanf(p,"%d",&utc);
if ((p=strtok(NULL,","))==NULL) return;
stat=p[0];
if ((p=strtok(NULL,","))==NULL) return; /緯度*/
sscanf(p,"%lf",&lat);
if ((p=strtok(NULL,","))==NULL) return;
ns=p[0];
if ((p=strtok(NULL,","))==NULL) return; /*経度*/
sscanf(p,"%lf",&lon);
if ((p=strtok(NULL,","))==NULL) return;
ew=p[0];

if (stat!='A') return;
printf("%02d時%02d分%02d秒(UTC) ",utc/10000, (utc%10000)/100, utc%100);
if (ns=='N') printf("北緯"); else if (ns=='S') printf("南緯");
printf("%.0lf度%.4lf分",floor(lat/100.0), fmod(lat,100.0));
if (ew=='E') printf("東経"); else if (ns=='W') printf("西経");
printf("%.0lf度%.4lf分",floor(lon/100.0), fmod(lon,100.0));
printf("\n");
}
int main(void) {
pnmea();
return 0;
}
(2)実行結果
14時35分14秒(UTC) 北緯34度28.9468分東経135度49.4507分

(1)で得たデータを(2)でGPRMCか判別し、必要な部分を取り出し表示 したいと考えています。よろしくお願いします。

A 回答 (5件)

こんな感じでどうでしょう?



#includeいろいろ
#include <strings.h> → #include <string.h>
#define いろいろ
char buf[512]; /* グローバル変数 */

void pnmea(void) {
関数の内容(bufの定義は消す)
}

int main(void) {
関数の内容(bufの定義は消す。pnmeaを呼び出す)
}
    • good
    • 0
この回答へのお礼

>JaritenCatさん
非常に参考になりました。
大変遅くなってしまい申し訳ありません、本当にありがとうございます。

お礼日時:2008/08/24 01:53

自分の勉強のためにNMEAパーサを書いてみるならそれはそれとして、私なら世の中にオープンソースで出ているNMEAパーサのソースコード見ちゃいます。

例えば http://sourceforge.net/projects/nmeap/ とか。

この回答への補足

>Interestさん回答ありがとうございます。
そのような方法でも学習できるのですね。勉強になりました。ありがとうございます。
そのページはひらくとエラーが発生してしまうので、他のサイトも探して勉強してみます。

補足日時:2008/08/08 16:02
    • good
    • 0

#include<string.h>


がインクルードされていないためstrtok( )関数の引数がint型と仮定されてしまっているようです

#include<strings.h>
がタイプミスではないでしょうか

この回答への補足

>php504さんありがとうございます。
本当ですね。すぐに変更して確認してみます。include文の誤りはエラーとして捕らえられないものなのでしょうか?
また、(1)と(2)を組み合わせたプログラムのとき、(2)の部分で扱われる”buf”は
res = read(fd,buf,512);
buf[--res]=0;
j++;
printf("%s\n",buf);
とあったprintf文に(2)のプログラムをほぼそのまま追加して表示方法を変更させたかったので、
res = read(fd,buf,512);
buf[--res]=0; /* 文字列終端をセット */
j++;
/*一行のNMEAセンテンスから時刻緯度経度のみを取り出すために、strtokで”,”ごとのトークンを得る*/
if ((p=strtok(buf,","))==NULL) return;
・・・・
のような形に変えたのですがこのような書き方で問題ないのでしょうか?

補足日時:2008/08/08 13:27
    • good
    • 0

Cは「関数を呼び出す際は、実体を宣言するか、実体を宣言しないならプロトタイプを宣言してから呼び出す」事になっています。



ライブラリ関数の実体やプロトタイプは、通常「#include文」で指定した、ライブラリヘッダファイルの中で行われています。

で、Cは「実体もプロトタイプも宣言されてない関数が呼び出された場合、関数へのすべての引数は、取りあえず、仮にすべてint型だと思っておく」と言う事をします。

その後で、関数の実体が現れたり、プロトタイプ宣言に出くわすと、引数の引き渡しを、その宣言部に書かれている引数の型に合わせ、暗黙のキャストを行います。

この時「仮にすべてint型だと思っていたら、実はポインタだった」と言う事が起き、それが原因で「引数にポインタを要求している関数で(実はポインタだったけど、仮にint型だと思われてしまい、結局はint型になっちゃった)int型の引数が渡されているので、キャストも何もしないでint型をポインタだと思いこんで渡したぞ」と言う警告が出ます。

たぶん「main関数は下に書く」と覚えたでしょうが、これは「呼ばれる関数を上に、呼び出している部分を下に書く事になり、関数の実体が宣言されたあとで、関数が呼び出されるので、いちいちプロトタイプ宣言しなくても済むから」です。

そういう訳で、
assignment makes pointer from integer without
の警告が出るのは
・「#include文」でヘッダファイルを読み込むのを忘れた
・プロトタイプ宣言するのを忘れている
・関数を宣言している部分よりも上(前)で、宣言前の関数を呼び出している
・関数に渡す引数の個数、タイプを間違っている
などです。

この回答への補足

>chie65536さん回答いただきありがとうございます。
assignment makes pointer from integer withoutを出してしまう要因についてとても参考になりました。
>(1)「#include文」でヘッダファイルを読み込むのを忘れた
>(2)プロトタイプ宣言するのを忘れている
>(3)関数を宣言している部分よりも上(前)で、宣言前の関数を呼び出している
>(4)関数に渡す引数の個数、タイプを間違っている
以下が組み合わせてつくってみたプログラムになります。
chie65536さんに頂いた例で確認すると(3)(4)に問題があるのでしょうか?

#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<strings.h>
#include<termios.h>
#include<stdio.h>
#include<math.h>

#define BAUDRATE B4800
#define MODEMDEVICE "/dev/ttyS0"

int main()
{
int fd, c, res;
int i=0;
int j=0;
int utc;
char stat;
char ns;
char ew;
char *p;
double lat;
double lon;
struct termios oldtio, newtio;
char buf[512];

if((fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY ))==-1){
perror(MODEMDEVICE);
exit(-1);
}

tcgetattr(fd, &oldtio); /*シリアルポートの設定を待避*/
bzero(&newtio, sizeof(newtio)); /*新しいポートの設定の構造体をクリア*/
newtio.c_cflag = (BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD);/*ボー:4800*/
newtio.c_iflag = (IGNPAR | ICRNL);
newtio.c_oflag = 0;
newtio.c_lflag = ICANON;
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);

while (i==0) {

res = read(fd,buf,512);
buf[--res]=0; /* 文字列終端をセット */
j++;
/*一行のNMEAセンテンスから時刻緯度経度のみを取り出すために、strtokで”,”ごとのトークンを得る*/
if ((p=strtok(buf,","))==NULL) return;
if (strcmp(p,"$GPRMC")!=0) return; /*センテンスの先頭は$GPRMCか?*/
if ((p=strtok(NULL,","))==NULL) return; /*utc:世界標準時*/
sscanf(p,"%d",&utc);
if ((p=strtok(NULL,","))==NULL) return; /*stat:ステータス*/
stat=p[0];
if ((p=strtok(NULL,","))==NULL) return; /*lat:緯度*/
sscanf(p,"%lf",&lat);
if ((p=strtok(NULL,","))==NULL) return; /*ns:南北*/
ns=p[0];
if ((p=strtok(NULL,","))==NULL) return; /*lon:経度*/
sscanf(p,"%lf",&lon);
if ((p=strtok(NULL,","))==NULL) return; /*ew:東西*/
ew=p[0];

/*時刻緯度経度に対応するトークン表示*/
if (stat!='A') return; /*ステータスチェック*/
printf("%02d時%02d分%02d秒(UTC) ",utc/10000, (utc%10000)/100, utc%100);
if (ns=='N') printf("北緯"); else if (ns=='S') printf("南緯");
printf("%.0lf度%.4lf分",floor(lat/100.0), fmod(lat,100.0));
if (ew=='E') printf("東経"); else if (ns=='W') printf("西経");
printf("%.0lf度%.4lf分",floor(lon/100.0), fmod(lon,100.0));
printf("\n");
printf("%d周目\n",j);
if(j==48)i++;/*NMEAセンテンス1セットは24行(12種と1行ずつのスペース)なのでここでは48行で2セット分のループ*/
}
tcsetattr(fd, TCSANOW, &oldtio); /* 退避させた設定に戻す */
close(fd); /* COM1のシリアルポートを閉じる */
return(0);
}

出力結果
rsgps.c: In function ‘main’:
rsgps.c:47: 警告: assignment makes pointer from integer without a cast
rsgps.c:49: 警告: assignment makes pointer from integer without a cast
rsgps.c:51: 警告: assignment makes pointer from integer without a cast
rsgps.c:53: 警告: assignment makes pointer from integer without a cast
rsgps.c:55: 警告: assignment makes pointer from integer without a cast
rsgps.c:57: 警告: assignment makes pointer from integer without a cast
rsgps.c:59: 警告: assignment makes pointer from integer without a cast

補足日時:2008/08/07 16:58
    • good
    • 0

その警告が出てるのはどの行?

この回答への補足

>Tacosanさん回答ありがとうございます。
(1)のprintf("%s\n",buf);
部分のかわりに(2)を入れてコンパイルしてみました。
while (i==0) {

res = read(fd,buf,512);
buf[--res]=0; /* 文字列終端をセット */
j++;
/*一行のNMEAセンテンスから時刻緯度経度のみを取り出すために、strtokで”,”ごとのトークンを得る*/
47行目→if ((p=strtok(buf,","))==NULL) return;
if (strcmp(p,"$GPRMC")!=0) return; /*センテンスの先頭は$GPRMCか?*/
if ((p=strtok(NULL,","))==NULL) return; /*utc:世界標準時*/
sscanf(p,"%d",&utc);
if ((p=strtok(NULL,","))==NULL) return; /*stat:ステータス*/
stat=p[0];
if ((p=strtok(NULL,","))==NULL) return; /*lat:緯度*/
sscanf(p,"%lf",&lat);
if ((p=strtok(NULL,","))==NULL) return; /*ns:南北*/
ns=p[0];
if ((p=strtok(NULL,","))==NULL) return; /*lon:経度*/
sscanf(p,"%lf",&lon);
if ((p=strtok(NULL,","))==NULL) return; /*ew:東西*/
ew=p[0];

/*時刻緯度経度に対応するトークン表示*/
if (stat!='A') return; /*ステータスチェック*/
printf("%02d時%02d分%02d秒(UTC) ",utc/10000, (utc%10000)/100, utc%100);
if (ns=='N') printf("北緯"); else if (ns=='S') printf("南緯");
printf("%.0lf度%.4lf分",floor(lat/100.0), fmod(lat,100.0));
if (ew=='E') printf("東経"); else if (ns=='W') printf("西経");
printf("%.0lf度%.4lf分",floor(lon/100.0), fmod(lon,100.0));
printf("\n");
printf("%d周目\n",j);
if(j==48)i++;/*NMEAセンテンス1セットは24行(12種と1行ずつのスペース)なのでここでは48行で2セット分のループ*/
}
tcsetattr(fd, TCSANOW, &oldtio); /* 退避させた設定に戻す */
close(fd); /* COM1のシリアルポートを閉じる */
return(0);
}

gcc -lm rsgps.c
rsgps.c: In function ‘main’:
rsgps.c:47: 警告: assignment makes pointer from integer without a cast
rsgps.c:49: 警告: assignment makes pointer from integer without a cast
rsgps.c:51: 警告: assignment makes pointer from integer without a cast
rsgps.c:53: 警告: assignment makes pointer from integer without a cast
rsgps.c:55: 警告: assignment makes pointer from integer without a cast
rsgps.c:57: 警告: assignment makes pointer from integer without a cast
rsgps.c:59: 警告: assignment makes pointer from integer without a cast

で以上のように出力されました。どのように組み合わせれば解決できるでしょうか?

補足日時:2008/08/07 16:10
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!