الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

تمرين في ال structures .

بدأه xpero في 16 نوفمبر 2010 · 14 رد · 1,438 مشاهدة · في الأسئلة المجابة
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم ورحمة الله تعالى وبركاته.

أتيتكم اليوم بتمرين حله سيعطيكم فكرة عن اشياء لا يعلمها الكثيرون حول ال structures. المهم هذا نص التمرين:

1- هل يوجد اختلاف بين هذين التركيبن :(اذا كان الجواب نعم قم بيتوضيح هذا الاختلاف)


struct abc{
double d;
int i;
char c;
};

و


struct def{
int i;
double d;
char c;
};

2- هل يمكن الوصول لعناصر التركيبين السابقين بدون استعمال المعاملين "." و "->"؟ وضح طريقة عمل ذلك اذا كان جوابك "نعم".

يمكن وضع الحلود في الموضوع ذاته لكي تعم الفائدة .بالتوفيق.

تم تعديل هذه المشاركة بواسطة xpero في 17 نوفمبر 2010 في 03:01

#2

ما أتذكره .... أنه يمكن الوصول لمحتويات التركيب بشئ من هذا القبيل:

struct abc *_abc;
*_abc = 10.0;		// set d
*(_abc+1) = 10;		// set i
*(_abc+2) = 'c';		// set c
#3

وعليكم السلام ورحمة الله وبركاته

سؤال جميل :)

رغم أنني لم أتعامل مع الـ C++ من فترة طويلة إلا أن فكرة الأخ هويدي جميلة جدا

وإن كانت إجابته نعم فربما الفرق في التعريفين السابقين إذا كنا سنعرف مؤشر إلى struct فيجب وضع القيم بالترتيب حسب التعريف

#4
هويدي كتب:

ما أتذكره .... أنه يمكن الوصول لمحتويات التركيب بشئ من هذا القبيل:

struct abc *_abc;
*_abc = 10.0;		// set d
*(_abc+1) = 10;		// set i
*(_abc+2) = 'c';		// set c

هذه الطريقة تعمل مع الجداول .. لكن لا تعمل دائما مع ال structures السبب هة ان عناصر هذه الاخيرة يمكن ان تكون لهم احجام مختلفة عكس الجداول التي تكون عناصرها من نفس الحجم.

عليك بتطوير الطريقة السابقة قليلا لكي تصل للحل.

#5

و عليكم السلام و رحمة الله و بركاته,

اقتباس
هل يوجد اختلاف بين هذين التركيبن :(اذا كان الجواب نعم قم بيتوضيح هذا الاختلاف)

نعم هناك اختلاف, لأن ترتيب الـ fields أصلاً مختلف! و يجب عليك كتابة الكود يدوياً إن كنت تريد نقل البيانات من الأول للثاني بشكل صحيح. و المترجم له الحق بوضع padding في أي مكان يحبه! أيضاً, للمعلومية فقط, هناك فرق بين C و ++C في هذه الناحية. تصور أن لدينا التالي:

struct first
{ int x; int y; };
struct second
{ int x; int y; };

هل هذان مختلفان؟ ليست لدي وثائق المقاييس حالياً لتأكيد ما أقول و لكن حسبما أذكر, في ++C هناك اختلاف بين first و second و لكن في C ليس هناك اختلاف. لأن ++C تعتمد على الاسم في تعيين مساواة الأنواع بينما C تعتمد على الـ structure الخاص بالـ struct.

اقتباس
هل يمكن الوصول لعناصر التركيبين السابقين بدون استعمال المعاملين "." و "->"؟

لماذا تريد عمل ذلك؟

#include <cstddef> // for offsetof macro

struct my_type
{ int x; int y; };

int main()
{
	my_type point;
	int *x_ptr, *y_ptr;
	x_ptr = (int*)((char*)&point + offsetof(my_type, x));
	y_ptr = (int*)((char*)&point + offsetof(my_type, y));
	*x_ptr = *y_ptr = 10;
	/*
	    point.x == 10;
		point.y == 10;
	*/
}

تم تعديل هذه المشاركة بواسطة Khaled.Alshaya في 16 نوفمبر 2010 في 23:34

#6
Khaled.Alshaya كتب:

و عليكم السلام و رحمة الله و بركاته,

نعم هناك اختلاف, لأن ترتيب الـ fields أصلاً مختلف! و يجب عليك كتابة الكود يدوياً إن كنت تريد نقل البيانات من الأول للثاني بشكل صحيح. و المترجم له الحق بوضع padding في أي مكان يحبه! أيضاً, للمعلومية فقط, هناك فرق بين C و ++C في هذه الناحية. تصور أن لدينا التالي:

struct first
{ int x; int y; };
struct second
{ int x; int y; };

هل هذان مختلفان؟ ليست لدي وثائق المقاييس حالياً لتأكيد ما أقول و لكن حسبما أذكر, في ++C هناك اختلاف بين first و second و لكن في C ليس هناك اختلاف. لأن ++C تعتمد على الاسم في تعيين مساواة الأنواع بينما C تعتمد على الـ structure الخاص بالـ struct.

نعم أخي هذا ما اردت الوصول له , يعني حسب ترتيب ال fields يتغير حجم ال structure للحفاظ على ال data alignement .

لماذا تريد عمل ذلك؟

#include <cstddef> // for offsetof macro

struct my_type
{ int x; int y; };

int main()
{
	my_type point;
	int *x_ptr, *y_ptr;
	x_ptr = (int*)((char*)&point + offsetof(my_type, x));
	y_ptr = (int*)((char*)&point + offsetof(my_type, y));
	*x_ptr = *y_ptr = 10;
	/*
    	point.x == 10;
		point.y == 10;
	*/
}

فقط للحصول على المزيد من المعلوماتlaugh.gif

شكرا لك أخي على المعلومات المفيدة.

#7
اقتباس
المترجم له الحق بوضع padding في أي مكان يحبه!

فى C++ لا يحق للمترجم ان يضع الـ padding إلا فى أخر POD object الذى تم إنشائه من class, struct or union و ذلك تبعا للقواعد التاليه الموجوده فى 2003 Standard:

1 - الجزء [intro.object] المقطع 5

اقتباس

Unless it is a bit-field (9.6), a most derived object shall have a non-zero size and shall occupy one or more

bytes of storage. Base class sub-objects may have zero size. An object of POD4) type (3.9) shall occupy

contiguous bytes of storage.

********************************

4) The acronym POD stands for "plain old data."

من الجزء الملون بالأزرق الـ Fields المكونه للكائن لابد و ان يتم وضعها بشكل متتالى و هذا يعنى إذا أراد المترجم وضع padding لابد أن يضعه فى نهاية الكائن.

2 - الجزء [class.mem] المقطع 17

اقتباس

A pointer to a POD-struct object, suitably converted using a reinterpret_cast, points to its initial

member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. [Note: There

might therefore be unnamed padding within a POD-struct object, but not at its beginning, as necessary to

achieve appropriate alignment. ]

فى الجزء الملون بالأزرق يعطى لنا تلميح بأن المترجم له الحق فى وضع padding كما يريد و لكن ليس فى بداية الكائن، بدمج هذا الجزء مع الأول يمكننا ان نستنتج أن المكان الوحيد المتاح للمترجم ان يقوم بوضع padding به بعد عناصر النوع.

*************************************

حتى يكون كلامي الموجود بالنقطه 1 صحيحا يرجى مراجعة هذا الرابط لمعرفة الشروط التى يمكن من خلالها معرفة ان كائن ما هو plain old data

و الله ولي التوفيق

تم تعديل هذه المشاركة بواسطة محمد علاء الدين في 17 نوفمبر 2010 في 03:52

1

مدونتي: C++ Tips and Tricks

#8
اقتباس
فى الجزء الملون بالأزرق يعطى لنا تلميح بأن المترجم له الحق فى وضع padding كما يريد و لكن ليس فى بداية الكائن، بدمج هذا الجزء مع الأول يمكننا ان نستنتج أن المكان الوحيد المتاح للمترجم ان يقوم بوضع padding به بعد عناصر النوع.

هذا صحيح, لا يمكن أن يكون هناك padding في أول الكائن. سقطت هذه النقطة في ردي السابق.

عموماً, سؤال. ماذا تقصد بـ "بعد عناصر النوع"؟ هل تقصد بعد جميع العناصر؟ أم يحق له وضع padding بعد أي بين أي عنصرين و في النهاية؟ :sleep:

تم تعديل هذه المشاركة بواسطة Khaled.Alshaya في 17 نوفمبر 2010 في 04:08

#9
اقتباس
ماذا تقصد بـ "بعد عناصر النوع"؟ هل تقصد بعد جميع العناصر؟ أم يحق له وضع padding بعد أي بين أي عنصرين و في النهاية؟

الـ POD object إذا كان من نوع class, strcut or union لابد و ان يحتوى على fields ذات انواع primitive او native arrays او pointers او fields من نوع POD type او arrays من نوع POD type.

فى حالتنا هذه تعريف التراكيب بالمشاركه الأولي يندرج تحت مفهوم POD type و بالتالى الـ padding ستكون فى نهايتهم، بمعنى ان المترجم سينظر للنوع abc كانه بالشكل التالى:

struct abc
{
    double d;
    int    i;
    char   c;
    char   __padding1,
           __padding2,
           __padding3; // compiler generated
};

يرجى مراجعة الرابط الموجود بالمشاركه السابقه لمعرفة المزيد عن POD types و POD objects.

و الله ولي التوفيق

مدونتي: C++ Tips and Tricks

#10
اقتباس
فى حالتنا هذه تعريف التراكيب بالمشاركه الأولي يندرج تحت مفهوم POD type و بالتالى الـ padding ستكون فى نهايتهم

هذا ليس شرطاً. يمكن أن يكون هناك padding بين d و i (أو, و) i و c (أو, و) في النهاية بعد c و ربما لا يكون هناك padding أصلاً.

#11
اقتباس
هذا ليس شرطاً. يمكن أن يكون هناك padding بين d و i (أو, و) i و c (أو, و) في النهاية بعد c و ربما لا يكون هناك padding أصلاً.

كلامك صحيح فقط إذا كان النوع يحتوى على دوال أو مشيد أو مهدم او virtual functions (إلى أخره)، فى هذه الحاله النوع ليس POD و بالتالى النقطه رقم 1 (بالمشاركه 7) سيتم تجاهلها و كل ما سيتم تنفيذه هو النقطه رقم 2 و هو إذا كان المترجم سيضع padding لابد أن لا تكون فى أول الكائن و لكن قد تكون بعد أى من الـ Fields الموجوده به.

لكن إذا كان النوع يحتوى على fields فقط فى هذه الحاله سينطبق عليه النقطتين 1 و 2 و بالتالى لابد و ان تكون الـ fields المكونه للكائن تحجز مساحات متتاليه من الذاكره و لهذا إن كان سيتم وضع padding فالمكان الوحيد المتاح هو بعد اخر Field.

و الله ولي التوفيق

تم تعديل هذه المشاركة بواسطة محمد علاء الدين في 17 نوفمبر 2010 في 16:20

مدونتي: C++ Tips and Tricks

#12

أخ محمد حديثي عن الـ POD أصلاً.

اقتباس
و لهذا إن كان سيتم وضع padding فالمكان الوحيد المتاح هو بعد اخر Field.

هذا ليس ما فهمته أنا من الـ standards, و لا ما فهمه صانعو المترجمات:

http://msdn.microsoft.com/en-us/library/71kf49f1%28VS.80%29.aspx

http://stackoverflow.com/questions/364483/determining-the-alignment-of-c-c-structures-in-relation-to-its-members/364491#364491

1
#13

كى يصبح كلامى مرتب سأتكلم عن نقطتين أولهم تتعلق بالـ POD و ثانيهما عن الـ alignment

1 - التالى هى النقاط التى تهمنا من الـ Standard و التى تتحدث عن الـ POD

اقتباس

[intro.object]

5 Unless it is a bit-field (9.6), a most derived object shall have a non-zero size and shall occupy one or more

bytes of storage. Base class sub-objects may have zero size. An object of POD type (3.9) shall occupy

contiguous bytes of storage.

[class.mem]

17 A pointer to a POD-struct object, suitably converted using a reinterpret_cast, points to its initial

member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. [Note: There

might therefore be unnamed padding within a POD-struct object, but not at its beginning, as necessary to

achieve appropriate alignment. ]

هذه النقاط تتلخص فى أن مساحة الذاكره المحجوزه لكائن من نوع ينطبق عليه مفهوم الـ POD لابد و أن تحجز مساحه متتاليه من الذاكره - أى ان جميع الـ bytes الموجوده من بداية العنوان بكامل مساحة الكائن هى ملك لهذا الكائن فقط، أيضا إذا المترجم سيقوم بوضع padding لابد و أن لا تكون فى أول الكائن.

2 - التالى هى النقاط التى تهمنا من الـ Standard و التى تتحدث عن الـ Alignment الخاصه بالكائن فى الذاكره

اقتباس

[basic.types]

5 Object types have alignment requirements (3.9.1, 3.9.2). The alignment of a complete object type is an

implementation-defined integer value representing a number of bytes; an object is allocated at an address

that meets the alignment requirements of its object type.

هذه النقطه تتلخص فى أن الـ alignment لكائن هى عدد من الـ bytes يعود للمترجم و ان العنوان الذى سيوضع فيه الكائن بالذاكره لابد و ان يفى بعملية الـ alignment.

**************************

الخلاصه:

وضع الـ alignment bytes بين الـ Fields لن يجعل هذه المساحه غير مملوكه للكائن (مما لا يخل بشروط الـ POD) و ايضا عدد الـ bytes هو implementation defined و مترجم vc يستخدم ناتج الرقم 2 مرفوعا للأس من 1 إلى 8192.

*************************

شكرا للأخ خالد على تصحيح معلوماتى و الروابط المفيده.

و الله ولي التوفيق

تم تعديل هذه المشاركة بواسطة محمد علاء الدين في 17 نوفمبر 2010 في 17:44

مدونتي: C++ Tips and Tricks

#14

شباب .... اشعر أننا خرجنا من الموضوع الأصلي لصاحب السؤال ... :D ...

#15
هويدي كتب:

شباب .... اشعر أننا خرجنا من الموضوع الأصلي لصاحب السؤال ... :D ...

التمرين وضعته بهذا الشكل عمدا .. هدفي من وضعه هو مناقشة امور ال alignement لتوضيح بعض الامور الغامضة لدي.happy.gif

و الحمد لله استفذت من النقاش.

مواضيع مشابهة