עזרה בקטע קוד C++
-
לצורך פרוייקט מסוים אני עובד על קוד שכתוב ב C++
אני כמעט לא מכיר את השפה.
אני מכיר php ו VBA ולכן אני כן מסתדר איכשהו..
נתקעתי בקטע שאני שולח בקשת POST לשרת ומקבל תשובה, את התשובה אני רוצה להכניס למשתנה סטרינג, ואני לא מצליח.זה קטע הקוד שמקבל את התשובה ומדפיס את התשובה בIDE.
// get lenght of document (is -1 when Server sends no Content-Length header) int len = http.getSize(); // create buffer for read uint8_t buff[128] = { 0 }; // get tcp stream WiFiClient * stream = http.getStreamPtr(); Serial.println(); // read all data from server while(http.connected() && (len > 0 || len == -1)) { // get available data size size_t size = stream->available(); if(size) { // read up to 128 byte int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size)); // write it to Serial Serial.write(buff, c); if(len > 0) { len -= c; } } delay(1); }
כאן נתקעתי בגלל חוסר הידע שלי ב C++.
אני לא מבין כלל מה הקטע קוד הזה עושה.
אני רוצה לשלוף את הטקסט למשתנה רגיל ואז להמשיך לבצע פעולות.
אך אני לא מצליח.הקטע:
Serial.write(buff, c);
מדפיס את הנתונים ל IDE.
אני רוצה לקבל את זה למשתנה לדוגמה:String test = "TEXT";
-
@איש-ימיני אמר:
אני לא מבין כלל מה הקטע קוד הזה עושה.
הקטע קורא זרם stream של בתים, מקטע מקטע. כל מקטע נקרא לתוך buffer בגודל 128 תוים. ובכל איטרציה של הלולאה מודפס המקטע שנקרא, ויש המתנה של אלפית שניה.
אני רוצה לשלוף את הטקסט למשתנה רגיל ואז להמשיך לבצע פעולות.
אם איך הכרח להשאר במגבלה של 128 תוים בכל פעם, אתה יכול לכתוב כך:
int len = http.getSize(); // get tcp stream WiFiClient * stream = http.getStreamPtr(); // declate a variable for the result std::string result; // read all data from server into string if (http.connected()) { // get available data size size_t size = stream->available(); if(size) { result.resize(size); // allocate space stream->read(&result[0], size); // read data from stream } } // now do whatever you want with the result
-
@איש-ימיני
היה כדאי שהיית מציין שמדובר בארדואינו ולא ++C רגיל
אני לא מכיר, אבל אני מתרשם שאין שם את הספרייות הסטנדרטיות של ++C בפלטפורמות אחרות
וגם נושא ניהול הזכרון שם שונה.הקוד שהבאת עובר בלולאה על התשובה מהשרת ובכל פעם שולף 128 בייטים ומדפיס אותם.
כדי לאסוף את התשובה המלאה למשתנה, תצטרך אחד מהשניים:- או להקצות מראש buffer בגודל של התשובה, ובכל איטרציה של הלולאה להעתיק לשם את המידע שמתקבל (אבל כדי ליישם את זה תצטרך לדעת מראש את גודל התשובה)
- או להשתמש ב-buffer בגודל דינאמי (לא יודע אם יש כזה דבר בקלות בארדואינו)
שים לב, שהקוד מודע לעובדה שלא תמיד תוכל לדעת מראש מה יהיה האורך של תשובת HTTP
is -1 when Server sends no Content-Length header
-
הקטע הבא אמור לעבוד בארדואינו:
while(http.connected() && (len > 0 || len == -1)) { // get available data size size_t size = stream->available(); if(size) { // read up to 128 byte int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size)); // write it to Serial USE_SERIAL.write(buff, c); // insert into string and send it to other function String segment = String((char *)buff); doSomething(segment); // decrease length if(len > 0) { len -= c; } } delay(1); } ... void doSomething(String segment) { // do your thing }
-
@yossiz כתב בעזרה בקטע קוד C++:
@איש-ימיני
היה כדאי שהיית מציין שמדובר בארדואינו ולא ++C רגילאני לא מכיר ++C ולכן לא חשבתי שזה שונה.
הקוד שהבאת עובר בלולאה על התשובה מהשרת ובכל פעם שולף 128 בייטים ומדפיס אותם.
כדי לאסוף את התשובה המלאה למשתנה, תצטרך אחד מהשניים:- או להקצות מראש buffer בגודל של התשובה, ובכל איטרציה של הלולאה להעתיק לשם את המידע שמתקבל (אבל כדי ליישם את זה תצטרך לדעת מראש את גודל התשובה)
- או להשתמש ב-buffer בגודל דינאמי (לא יודע אם יש כזה דבר בקלות בארדואינו)
כפי שכתבתי יש לי חוסר ידע בסיסי ב ++C.
אני אפילו לא יודע מה זה buffer, ואיך עובדים איתו, אני מכיר משתנים ומערכים מ phpו VBA.
הייתי רוצה משהו כזה:String test = ""; test += Serial.write(buff, c);
אבל בפועל זה עושה מה שאני רוצה, במקום הטקסט של התשובה אני מקבל מספרים לא ברורים.
וסליחה על הבורות. -
@איש-ימיני כתב בעזרה בקטע קוד C++:
אני לא מכיר ++C ולכן לא חשבתי שזה שונה.
זה תשובה משונה.
אם אתה לא מכיר C++ עוד יותר מתבקש שתכתוב מה זה כן ולא מה נראה לך.
אתה לא צריך להתנצל על אי ידע, אבל לעזור לעונים לנחות מהר לעניין. -
@איש-ימיני buffer הוא אוגר. כאשר המידע מועבר בצורה לא רציפה, משתמשים ב-buffer כדי לקרוא את המידע בחתיכות.
לגבי היישום, תבדוק את הקטע האחרון שצירפתי. בפונקציה doSomething אתה יכול ליישם איזו לוגיקה שאתה רוצה.
למשל, בהנחה שיש לך משתנה מחרוזת גלובלי בשם result, אתה יכול להוסיף את המקטע למחרוזת:void doSomething(String segment) { result += segment; }
-
@OdedDvir כתב בעזרה בקטע קוד C++:
הקטע הבא אמור לעבוד בארדואינו:
נראה לי ש-
segment.getBytes
עושה הפוך ממה שהתכוונת,
https://www.arduino.cc/reference/en/language/variables/data-types/string/functions/getbytes -
@OdedDvir כתב בעזרה בקטע קוד C++:
@איש-ימיני buffer הוא אוגר. כאשר המידע מועבר בצורה לא רציפה, משתמשים ב-buffer כדי לקרוא את המידע בחתיכות.
לגבי היישום, תבדוק את הקטע האחרון שצירפתי. בפונקציה doSomething אתה יכול ליישם איזו לוגיקה שאתה רוצה.
למשל, בהנחה שיש לך משתנה מחרוזת גלובלי בשם result, אתה יכול להוסיף את המקטע למחרוזת:void doSomething(String segment) { result += segment; }
ניסיתי.
result נשאר ריק. -
@איש-ימיני זה בגלל שהיתה לי טעות בקוד, כמו שציין @yossiz. תיקנתי במקור והפכתי את ההשמה ל:
// insert into string and send it to other function String segment = String((char *)buff);
ובעצם אפשר ישר כך:
doSomething(String((char *)buff));
-
אני רואה בפורומים של ארדואינו שממליצים לא להשתמש ב-
String
אולי יש מקומות שבהם זה בסדר להשתמש אבל צריך להיות מודע להשלכות
-
@yossiz לכאורה אפשר לוותר על זה לגמרי, אבל אז צריך לשלוח גם את הגודל של המערך (כי אין null char בסוף)
// cast into char array and send it to other function doSomething((char *)buff, c); ... void doSomething(char * segment, int size) { // do your thing }
-
@OdedDvir יש פה בעיה,
הקוד שלך עובד על כל פלח של 128 בייטים בנפרד,
הוא רוצה לאסוף את כל הפלחים למשתנה אחת
אבל האורך של המחרוזת המלאה לא ידועה מראש בצורה סטטית,
זה מחייב הקצאת זכרון דינאמי
משיטוט קצר ברשת נראה שזה נושא מתקדם ולא כזה פשוט בארדואינו,
מינימום צריך להכיר קצת את השפה והפלטפורמה לפני מימוש של דבר כזה@איש-ימיני אם במקרה, ידוע מראש שהתשובה לא יארוך יותר מ-X תווים, או שלא תצטרך יותר מ-X תווים מהתשובה, זה יפשט בהרבה את הפתרון
-
@OdedDvir כתב בעזרה בקטע קוד C++:
@איש-ימיני זה בגלל שהיתה לי טעות בקוד, כמו שציין @yossiz. תיקנתי במקור והפכתי את ההשמה ל:
// insert into string and send it to other function String segment = String((char *)buff);
ובעצם אפשר ישר כך:
doSomething(String((char *)buff));
האם הקוד הזה מסתמך על ה-null byte כדי לציין את סוף המחרוזת? כי במקרה הזה אין null byte, או שיש במקום לא נכון...
עריכה: אני רואה עכשיו ששמת לב לנושא בפוסט אחר -
@OdedDvir כתב בעזרה בקטע קוד C++:
@yossiz לכאורה אפשר לוותר על זה לגמרי, אבל אז צריך לשלוח גם את הגודל של המערך (כי אין null char בסוף)
// cast into char array and send it to other function doSomething((char *)buff, c); ... void doSomething(char * segment, int size) { // do your thing }
הפתרון הזה עובד טוב מאוד.
עזרת לי מאוד.
תודה רבה. -
@OdedDvir כתב בעזרה בקטע קוד C++:
מעכשיו אני אשתדל לשבת בשקט
ככל הנראה פתרת לו את הצורך לבינתיים (עד שזה יקרוס מסיבה עלומה ואז נשמע ממנו שוב...)
@איש-ימיני חשוב להבין ששפת ++C לא דומה כלל ל-php או vba
יש ב-++C הרבה הזדמנויות לעשות טעויות קטנות שלא תשים לב עליהם ואף אחד לא יתריע לך עד שפתאום משהו (שנראה) לא קשור לגמרי יתפוצץ לך בפנים ולא תבין מאיפה זה בא לך
כל זה תוצאה של חסרון "אבטחת זכרון" (memory safety) של השפה