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

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

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

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

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

Q&A

解決済

2回答

632閲覧

【Arduino】 ネストされた構造体変数へ意図しない代入がされる

yuusakuri

総合スコア6

C

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

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

0グッド

0クリップ

投稿2022/08/29 14:05

編集2022/08/31 09:54

前提

ArduinoとM5StickCを使っています。ターミナルとはBluetooth接続です。
ターミナルからのコマンドを解析し、設定を付与した上で処理するプログラムを書いています。問題があるのはコマンドを解析するプログラムです。

実現したいこと

ターミナルから受け取った文字列をスペースによって分割し、予め定義してある構造体に入れるようプログラムしたいです。
しかし、for文内のコメントの箇所にて構造体変数に意図しない代入がされます。
ターミナルからst 1111111と送信すると、構造体変数のコマンド名の部分には最終的に、stが入って欲しいのですが、パラメータ値の1111111が代入されます。
パラメータは、コマンド名 -パラメータ名 パラメータ値でも、コマンド名 7桁の数字でも、両方で動作してほしいので、少々回りくどい書き方のプログラムです。

該当のソースコード

arduino

1#include <M5StickC.h> 2#include <BluetoothSerial.h> 3#include "utility/MPU6886.h" 4 5#define logout SerialBT.println(__LINE__) 6 7// BT 8BluetoothSerial SerialBT; 9uint64_t chipid; 10char chipname[256] = "m5hoge"; 11 12// flags 13byte commandStatusCode = 0; 14 15// パラメータ名, パラメータ値を持ちます 16struct m5CommandParam { 17 String name, value; 18}; 19 20// コマンド名とパラメータセット(パラメータ名, パラメータ値)を持ちます 21struct m5Command { 22 String name; 23 struct m5CommandParam params[20]; 24 int paramsCount = 0; 25}; 26 27// コマンドを解析し、引数のm5Commandに解析されたコマンドのデータをセットします。 28void parseCommand(String receivedString, struct m5Command *parsedCommand) { 29 int splitedReceivedStringCount = 0; 30 String splitedReceivedString[20]; 31 receivedString.trim(); 32 33 if (receivedString.length() < 0) { // 受け取ったコマンドが空だった場合 34 commandStatusCode = 1; 35 return; 36 } 37 38 while (receivedString.length() > 0) 39 { 40 int spaceIndex = receivedString.indexOf(' '); 41 splitedReceivedStringCount++; 42 if (spaceIndex == -1) // No space found 43 { 44 splitedReceivedString[splitedReceivedStringCount - 1] = receivedString; 45 break; 46 } 47 else 48 { 49 splitedReceivedString[splitedReceivedStringCount - 1] = receivedString.substring(0, spaceIndex); 50 receivedString = receivedString.substring(spaceIndex + 1); 51 } 52 } 53 54 if (useShortCommand) { 55 bool is7digit = splitedReceivedString[1].length() == 7; 56 if (!is7digit) { 57 SerialBT.println("!is7digit"); 58 commandStatusCode = 2; 59 return; 60 } 61 62 splitedReceivedStringCount++; 63 splitedReceivedString[splitedReceivedStringCount - 1] = "-Delay"; 64 splitedReceivedString[splitedReceivedStringCount++] = splitedReceivedString[1].substring(0, 3); 65 66 splitedReceivedString[splitedReceivedStringCount++] = "-ShouldGetAccelAdc"; 67 splitedReceivedString[splitedReceivedStringCount++] = splitedReceivedString[1][3]; 68 69 splitedReceivedString[splitedReceivedStringCount++] = "-Afs"; 70 splitedReceivedString[splitedReceivedStringCount++] = splitedReceivedString[1][4]; 71 72 splitedReceivedString[splitedReceivedStringCount++] = "-ShouldGetGyroAdc"; 73 splitedReceivedString[splitedReceivedStringCount++] = splitedReceivedString[1][5]; 74 75 splitedReceivedString[splitedReceivedStringCount++] = "-Gfs"; 76 splitedReceivedString[splitedReceivedStringCount++] = splitedReceivedString[1][6]; 77 } 78 79 // 空白によって区切られた文字列をm5Commandに変換する 80 parsedCommand->name = splitedReceivedString[0]; // この時点でparsedCommand->nameは'st' 81 82 // todo: debug 83 SerialBT.printf("Debug: Line: '"); 84 logout; 85 SerialBT.printf("parsedCommand.name: '"); 86 SerialBT.print(parsedCommand->name); 87 SerialBT.printf("'"); 88 SerialBT.println(""); 89 90 for (int i = 1; i < splitedReceivedStringCount; i++) { 91 // todo: debug 92 SerialBT.printf("Debug: Line: '"); 93 logout; 94 SerialBT.printf("i: '"); 95 SerialBT.print(i); 96 SerialBT.printf("', "); 97 SerialBT.printf("parsedCommand.name: '"); 98 SerialBT.print(parsedCommand->name);//ここではstと出力される 99 SerialBT.printf("'"); 100 SerialBT.println(""); 101 bool isParamName = splitedReceivedString[i][0] == '-'; 102 if (isParamName) { 103 parsedCommand->paramsCount++; 104 parsedCommand->params[parsedCommand->paramsCount - 1].name = splitedReceivedString[i]; 105 } else { 106 parsedCommand->params[parsedCommand->paramsCount - 1].value = splitedReceivedString[i]; //問題のか所。この行を消すとparsedCommand->nameは'st'のままだが、残すとi:1の際にparsedCommand->nameが1111111となる。 107 } 108 } 109 110 // todo: debug 111 SerialBT.printf("Debug: Line: '"); 112 logout; 113 SerialBT.printf("parsedCommand.name: '"); 114 SerialBT.print(parsedCommand->name); // ここで1111111と出力されるが、stと出力されるのを想定している。 115 SerialBT.printf("'"); 116 SerialBT.println(""); 117 SerialBT.printf("parsedCommand.paramsCount: '"); 118 SerialBT.print((String)parsedCommand->paramsCount); 119 SerialBT.printf("'"); 120 SerialBT.println(""); 121} 122 123// シリアルから送られてきたコマンドを実行する 124void executeCommandFromSerial() { 125 if (SerialBT.available() > 0) { // バッファにデータがある場合 126 receivedFromTerminal = SerialBT.readStringUntil('\r'); // ターミナルから送信された文字列をCRの手前まで取得 127 SerialBT.println(receivedFromTerminal); 128 if (receivedFromTerminal.isEmpty()) { 129 SerialBT.println("isEmpty"); // todo: remove 130 commandStatusCode = 1; 131 return; 132 } 133 134 // コマンドを解析する 135 struct m5Command parsedCommand; 136 parseCommand(receivedFromTerminal, &parsedCommand); 137 } 138} 139 140void setup() { 141 // M5 142 M5.begin(); 143 M5.Lcd.setRotation(3); 144 M5.Lcd.fillScreen(BLACK); 145 M5.Lcd.printf("Bluetooth: %s\n", chipname); 146 sensorInit(); 147 148 //BT 149 chipid = ESP.getEfuseMac(); 150 SerialBT.begin(chipname); 151 SerialBT.setTimeout(10 * 1000); 152} 153 154void loop() { 155 executeCommandFromSerial(); 156}

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

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

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

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

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

nac_tnk

2022/08/31 00:54

実際の所、 SerialBT.print((String)parsedCommand->paramsCount); は幾つだったの?
guest

回答2

0

意図しない代入がされる

ってのは非常にあるあるな話で、どこかで不正アクセスが起こっている、ということです
C/C++では実行時の異常チェックは行われないため、コードの異常はあなたががんばって見つけないといけません

投稿2022/08/30 23:00

y_waiwai

総合スコア87719

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

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

0

ベストアンサー

問題のelseに入った時点で、parsedCommand->paramsCount が0だからでは。最初のコマンド名はーから始まらないので、paramsCount++されないので。
未定義動作だけど、params[-1]->valueは、m5Commandのparams先頭からString1個分もどるアドレスを指すので、m5Command のnameの位置になるという話。

投稿2022/08/29 15:17

matukeso

総合スコア1590

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問