העתקת ערך int למערך char

כרמית ש1

New member
העתקת ערך int למערך char

שלום,
אני צריכה לבנות מערך עם נתונים לשליחה. המערך מסוג char ואמור להכיל נתונים שונים הכולליים data (באסקי), ונתונים נוספים עבור זיהוי ובדיקת נתונים (מספר id כלשהו, סימן לתחילת טקסט, סימן לסוף טקסט, גודל ה data שנשלח, crc וכו').
שאלתי היא: הוקצו לי 2 בתים במערך לגודל ה data שנשלח. הגודל כמובן הוא ב int. כיצד אני מעתיקה את נתון ה int ל 2 הבתים במערך? (נאמר לי לא להמיר int ל char אלא להעתיק אותו כ int. להעתיק את 2 הבתים של ה int (אחרי casting ל short) למקום הנכון במערך).
איך מבצעים העתקה כזו?
תודה רבה!
 

BravoMan

Active member
בהנחה שאין בעיית כיווניות שמירה בין

מה שאמור להישלח לפלטפורמה שממנה זה נשלח, למה לא להעתיק פשוט את הזיכרון, אחד לאחד?

ראשית, אם מדובר במוצר ולא בשיעורי בית כדאי מאוד לוודא שהערך ב-int אכן נכנס לשתי בית. זה בדיוק מסוג המקומות ש-buffer overflow ו-buffer underflow נוהגים לצוץ וליצור פרצות אבטחה מפחידות!

שנית, אם את הולכת להמיר ל-short יש לוודא ש-short הוא אכן 2 בית בפלטפורמה שאת מקמפלת אליה!
זכרי שב-C גודל טיפוסים הוא תלוי פלטפורמה!

אם הוא לא, תבדקי מה הכיווניות (big / little endian) ואל תמירי אלה תיקחי את החלק הרלוונטי של המשתנה המקורי!


אחרי זה, אפשר פשוט להעתיק את הזיכרון:
#define SIZE_OFFSET x /* this is the location of size field in the buffer */int size;
short s_size;
char buffer[SIZE_OF_BUFFER];s_size = (short)size;memcpy(buffer + SIZE_OFFSET, &s_size, sizeof(s_size));
 

כרמית ש1

New member
זה מה שעשיתי. אבל...

זה לא עבד טוב. רק עכשיו הבנתי כנראה למה...
כאשר הגודל קטן מ 255 זה פשוט לא עובד! (כי byte אחד למעשה 0? )
ברגע שהגודל גדול יותר מ 255 זה עובד.
אז מה עושים אם הגודל קטן מ-255?
תודה רבה!
 

BravoMan

Active member
מה שכתבת אינו הגיוני...

מה זאת אומרת - "לא עובד טוב"?
מה הבעיה עם זה שבית אחד הוא 0? ככה זה אמור להיות.
ובכל מקרה, memcpy מעתיק כל בית בדיוק כפי שהוא לא משנה מה ערכו.
&nbsp
את יכולה לפרסם את קטע הקוד הרלוונטי?
וקלט \ פלט לדוגמה?
נניח שהגודל הוא 1, מה מתקבל?
&nbsp
המקרה היחיד שזה אמור להישבר הוא אם יש ערך גדול יותר ממה ש-short יכול להכיל, למשל, 40000, במקרה כזה יש לעבוד עם unsigned.
אם יש ערכים עוד יותר גדולים, למשל 70000, אז בכל מקרה 2 בית לא מספיקים לייצוג.
 

כרמית ש1

New member
הפרדתי רק את הקוד הרלוונטי...

&nbsp
void func(unsigned char * buff)
{
unsigned short data_length;
&nbsp
data_length = 19;
&nbsp
buff[0]=0x01;
buff[1]=0x02;
memcpy(buff+2, (char*)&data_length,2);
&nbsp
הדיבאגר מציג:
buff "\001\002\023"
strlen(buff) מחזיר לי 3 ולא 4.
למה??
(כאשר שמה למשל ערך של 272 במקום 19 אז המערך בגודל 4)
&nbsp
תודה רבה!
&nbsp
}
 

BravoMan

Active member
כי strlen לא נועד לעשות את מה שאת רוצה

שהוא יעשה.
&nbsp
ה-buffer שלך מכיל נתונים בינאריים. הוא מייצג מבנה שנארז למשלוח.
למה את רוצה להפעיל עליו את הפונקציה strlen?
&nbsp
זו פונקציה שנועדה למדוד אורך מחרוזות, והיא עוצרת ברגע שהיא רואה תו שערכו 0, כי לפי הסטנדרט של השפה תו שערכו 0 הוא תו נועל שמסמן סוף מחרוזת.
&nbsp
אם הפונקציה שלך לא מקצה בעצמה את buff, היא אמורה לקבל גם את הגודל שלו כפרמטר, כי ב-C אין דרך לדעת מה גודל ה-buffer שאליו מצביע מצביע מסוים רק דרך אותו מצביע.
&nbsp
זה משפט קצת מבלבל, אבל בקיצור אין לך דרך לדעת מה גודל buff אם לא ישלחו לך אותו בנפרד!
 

כרמית ש1

New member
אבל עדיין יש בעייה...

הנתון הבא שאני מכניסה למערך אמור להכנס למערך במקום ה-4 (כי נתון ה length אמור להיות 2 בתים). אבל הוא נכנס למקום ה -3. כי המקום ה - 3 במערך למעשה פנוי.
אני יכולה לכפות עליו לאיפה להכניס את הנתונים, אבל זה תקין שבאמצע המערך יש למעשה 0 (NULL)? (הרבה פונקציות לא יעבדו טוב עם מערך שמכיל בתוכו 0...)
&nbsp
 

Grosseto

New member
אין לנו כמתכנתים שליטה על זה

יש מ"ה ששמות בבית הימני את החלק הפחות משמעותי של הביטים , כמו למשל VAX של דיגיטל, ויש מערכות כמו ווינדוס ששמות בבית הימני את הביטים היותר משמעותיים.
&nbsp
זה תקין מאוד שיש באמצע מערך 0, אם מתיחסים אליו כמערך בינרי ולא ליטרלי
 

BravoMan

Active member
לנו כמתכנתים יש שליטה מוחלטת על הכל!

בהרבה תוכנות יש צורך להמיר endiness מהארכיטקטורה הטבעית של המערכת עליה רצה התוכנה לארכיטקטורה אחרת.
&nbsp
למשל network byte oreder הוא big endian בעוד שכל מערכת x86 הן little endian ולכן מי שעובד עם sockets, ip וכו' משתמש בפונקציות המרה!
 

BravoMan

Active member
אין דבר כזה "מקום פנוי" במערך.

מקום פנוי הוא מקום שאת כמתכנתת מחליטה שהוא פנוי.
המחשב לא מחליט, מבחינתו, בכל תא ותא בזיכרון תמיד יש ערך כלשהו, ולא משנה אם יש לו משמעות ואם מישהו משתמש בו.
&nbsp
תו 0 אינו NULL. אלה דברים שונים, למרות שבהרבה מקרים יש להם אותו ערך מספרי.
&nbsp
בכל מקרה, זה שאת עובדת עם מערך מסוג "char" לא אומר שאת עובדת עם מחרוזת.
את עובדת עם נתונים בינאריים מסוגים שונים. במקרה כזה, אסור לך להשתמש בפונקציות שנועדו לעבוד עם מחרוזות כמו strlen, ולכל מספר יש משמעות שונה ממה שהיית לו במחרוזת.
&nbsp
גם אם חלק מהתאים במערך אמורים להכיל ערכים שיתפרשו כטקסט, זה לא משנה.
המערך למעשה מכיל מבנה, ותא אמורה לצפות לכל ערך אפשרי בכל תא!
&nbsp
אין שום סיבה שאם תרצי שערך יכנס לתא 4 במערך הוא יכנס לתא 3, אלא אם כתבת שהוא יכנס לתא 3.
תכתבי define עם מיקומים בתוך מערך של כל שדה ושדה, ותדאגי להעתיק ערכים לפי המיקומים הנכונים, ולא לפי strlen!
 

כרמית ש1

New member
אם אני מבינה נכון...

אם השתמשתי, למשל, ב strcat זה גם לא יעבוד. פשוט חייבת לעבוד לפי מיקום ספציפי במערך.
&nbsp
 

BravoMan

Active member
מן הסתם.

את חייבת להבין - char הוא טיפוס נתונים שמכיל מספרים שלמים קטנים, בד"כ מ127 עד -128
&nbsp
הם לא חייבים להתפרש כתווים. זה שימוש אחד נפוץ אבל הוא לא מחייב, וזה לא השימוש בתוכנה שלך!
פונקציות שמתחילות ב-str נועדו לעבוד רק על מחרוזות - מערכים שמכילים רק טקסט תקני ואמורים להתפרש כטקסט.
&nbsp
מה שיש לך, זה למעשה מבנה - struc ששיטחו אותו למערך, כנראה לצורך שמירה לקובץ או שליחה ברשת.
&nbsp
את צריכה להתייחס אליו ככזה, ולהשתמש בפונקציות העתקת זיכרון כגון memcpy, והצבות ישירות לפי אינדקסים.
 

כרמית ש1

New member
הבנתי...

אכן אני פשוט הייתי תקועה במחשבה שהמערך מכיל תווים... ואכן זה לא המצב כרגע.
תודה רבה!!! עזרת לי המון!!!!!!!!!!
 

BravoMan

Active member


 

כרמית ש1

New member
האם הביטויים שקולים?

האם 2 הדרכים הבאות מבצעות את אותו הדבר?
1) memcpy(buff+2, (char*)&data_length,2)
&nbsp
2) buff[2] = data_length & 0xFF
buff[3] = (data_length >> 8) & 0xFF
&nbsp
 

Grosseto

New member
יש הבדל בין INT ל SHORT

עד כמה שידוע לי SHORT תמיד יהיה בגודל שני בתים (להבדיל מ INT שיכול להיות 2 או 4).
&nbsp
נניח שזה כך, הייתי נוטה להשתמש ב UNION. למשל כך:
&nbsp
void func(unsigned char * buff)
{
&nbsp
&nbsp
&nbsp
union Data
{
unsigned short data_length;
&nbsp
char str[2];
};
&nbsp
union Data data;
&nbsp
data.data_length = 19;
&nbsp
buff[0]=0x01;
buff[1]=0x02;
&nbsp
buff[2]=data.str[0];
buff[3]=data.str[1];
&nbsp
}
&nbsp
&nbsp
&nbsp
 

Grosseto

New member
קצת הסבר למתחילים לגבי 023

מדובר בעצם ב 19 בבסיס 8
&nbsp
כלומר 023=0x13=19
&nbsp
את יכולה לבקש מהדיבגר באיזה בסיס להציג את המשתנים
 
למעלה