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

الpointer cast و bus error

بدأه apex في 7 يوليو 2010 · 8 رد · 729 مشاهدة · في الأسئلة المجابة
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

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

ساكتب فى الموضوع ولكن ارحب باى تغييرات او اصلاحات لان الفكرة مشوشة عندى .

المصدر

Bus_error

كثيرا من الكتب تقوم بشرح الترتيب الهرمى للمتغيرات وايهم قابل للcasting دون فقد معلومات وايهم لا , ولكن غالبا ما يهملون الحديث عن الpointer cast .

كثيرا من المعالجات قادرة على عنونة البايت الواحد ولكن عند عنونة الاحجام الاكبر (2 و4 فيما اعلى ) يجب ان تكون تلك البيانات مرتبة aligned (مرتبة فى الذاكرة فى عنواين مضاعفة للقيمة 1002 , 1004 مثلا عند حفظ بيانات بحجم 2 byte )

لذلك اذا قمت بعمل cast مثلا لموشر على char لاخر لint فانت بذلك ستجعل المتغير الint الذى يوشر علية int* فى وضع غير aligned (لانة مازال char size aligned ) وهنا عند عمل dereference سيقوم بانتاج bus error

وهناك بعض المقالات الاخرى تقول انها ستوثر على الاداء لان المعالج سيقوم بعمل access للذاكر بنفس طريقة الalign القديمة فسيحضر البيانات على عدة دورات access بدل دورة واحدة وقد يسوء الامر اذا كان المعالج يستخدم الcache

line ولنفترض حجمة 64 بايت و لسوء الحظ البيانات التى تريدها تقع فى نهاية cache line وفى بداية التالى لة فلذلك سيقوم المعالج بعمل كاش ل128 كيلو لعمل احضار لكمية بيانات ضئيلة .

name : mohamedyosry

#2

يا أخى, هلا تحدثت بطريقة أكثر بساطه wacko.gif

#3
اقتباس

لذلك اذا قمت بعمل cast مثلا لموشر على char لاخر لint فانت بذلك ستجعل المتغير الint الذى يوشر علية int* فى وضع غير aligned (لانة مازال char size aligned ) وهنا عند عمل dereference سيقوم بانتاج bus error

memory alignment داخل معالجات انتل هى مجرد optimizations لتقليل عدد الـ cycles المطلوبه لعمل fetch للبيانات من الذاكره داخل الكاش قبل ارجاعها إليك، سبب انها غير اساسيه يعود لتنوع الـ opcodes التى تقوم بنفس العمليه، أيضا misaligned memory ستجعل برنامجك ابطأ كثيرا لذا حاول ان تقلل منها قدر استطاعتك.

إذا تكلمنا عن RISC او NISC ستجد أن memory aligned هى مسأله اساسيه و بدونها ستفشل العمليه التى تقوم بها و سيتطلب منك غلق برنامجك و هذا الكلام يحدث ايضا داخل بيئة Itanum و لكن هنا تعتمد على نظام التشغيل ففى حالة ويندوز يقوم برمى الإستثناء EXCEPTION_DATATYPE_MISALIGNMENT و بعدها سيقوم بعمل اغلاق لبرنامجك.

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

دخل اللغه يمكنك استخدام

__declspec(align(#))

لتجبر المبرمج ان يقوم بعمل align للكائن داخل الذاكره، هذه الكلمه بهذا الشكل السابق تعمل على مترجم VC و Intel بكفائه و يمكنك مراجعة وثائق GCC لمزيد من المعلومات عنها.

هذا الموضوع too low level و مكانه الأفضل داخل قسم الأسمبلى إن اردت معلومات افضل بهذا الشأن. و لكن هذا الخيار يعود لك. :)

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

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

2

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

#4

من عنيا يا هويدى

الامر وبكل بساطة ان الpointer هو متغير يحفظ عنوان متغير اخر .

اذن الموشر لchar يحوى عنوان الchar والموشر لint يحوى عنوان int

النقطة ان المعالجات تتطلب ان تكون البيانات التى اكبر من 1 byte ان تكون aligned (مثلا اذا كان مصفوفة متغيرات بحجم العنصر 2 بايت فتحفظ على عنواين مضاعفة للحجم مثلا 500 و 502 492 وليس عنوان ليس من مضاعفات حجم العنصر مثل 501 503 491 )

حسنا ما الخطاء عند عمل cast لchar* ل int* ؟

الخطاء ان تعطى int* عنوان ذاكرة مهيى لحفظ char وليس int ولذلك عند استعمال الint* بعد ذلك (عمل dereference ) يحصل خطاء على بعض الاجهزة يسبب crash تسمى bus error وعلى بعض االاجهزة تضاعف عدد االaccess لجلب البيانات

واى حاجة انا فى الخدمة

name : mohamedyosry

#5
اقتباس
هذا الموضوع too low level و مكانه الأفضل داخل قسم الأسمبلى إن اردت معلومات افضل بهذا الشأن. و لكن هذا الخيار يعود لك.

شكرا يا اخى محمد

فقط ابحث عما يقينا شر الcrash و regression :lol:

اقتباس
دخل اللغه يمكنك استخدام

__declspec(align(#))

لكن اليس الoptimaztion flags اضمن ?

name : mohamedyosry

#6
اقتباس
حسنا ما الخطاء عند عمل cast لchar* ل int* ؟

مم, تقصد أنه في حالة ال char* سيشير على عنوان مثلا 500 و تكون العناوين التابعه 501 و 502 و 503

أما في حالة int* فإن العناوين يجب أن تكون تقبل القسمه على 5 مثلا 500 و 504 و هكذا

#include <stdio.h>

int main(void)
{
	char arr[]  = {1, 2, 3};
	char* chr_ptr = arr;
	/*
	say &arr[0]  = 500, so
	&arr[1] may be 501 and
	&arr[2] may be 502.
	*/

	int *int_ptr = (int*)chr_ptr;
	printf("%i\n", *++int_ptr); // should now refere to arr[1] and this may cause BUS, right?
	// on MS VS2008 it prints garbage data (-858993460) instead of 2

	return 0;
}

أستخلص من ذلك أنه لا يجوز علم pointer casting مطلقا؟؟

شكرا يا أخي, و جزا الله خيرا..

#7
اقتباس
فقط ابحث عما يقينا شر الcrash و regression :lol:

إذا كان برنامجك سيعمل على معالج من فئة CISC فلا تقلق حيال هذا الأمر و إذا كان المعالج من فئة اخرى فأنت فعلا تحتاج لأن تعيد التفكير فى الأمر فالمترجم يقوم بعمل alignment بشكل تلقائي مثلا انظر حجم هذا الـ struct و قارن بين المساحه الفعليه التى يحجزها (عن طريق حسابها باليد) و المساحه التى يعيدها المعامل sizeof

#include <stdio.h>

struct test
{
	short a;
	char  r;
};

int main()
{
	printf("size of test is %i bytes.\n", sizeof(test));
}

الوقت الحقيقى الذى تحتاج ان تقلق حيال هذا الأمر عندما تعمل مع مسجلات تتطلب منك ان تكون مؤشرات تم عمل align لها بمساحه معينه، حينها لابد منك ان تقعل كل ما يتطلبه الأمر منك حتى تتجنب حدوث crash لبرنامجك.

اقتباس
لكن اليس الoptimaztion flags اضمن ?

هل تقصد التى يتم تمريرها للمترجم، إذا كنت تقصدها فلا ليست اضمن فى بعض الحالات فمثلا عندما تتعامل مع تعليمات MMX او SSE فما اعلى يتطلب ن يكون المؤشر الذى لديك يشير إلى منطقه فى الذاكره تم عمل alignment لها لـ 64 بايت، حينها تحتاج لإعطاء هذه المعلومه للمترجم بشكل صريح.

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

1

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

#8

لم يعمل على VS 2008, لذا قمت بالتعديل:

#include <stdio.h>

typedef struct
{
  	short a;
  	char  r;
}Test;

int main()
{
	Test test;
	printf("size of test is %i %i bytes.\n", sizeof(Test), sizeof(test));
}

و هو يعطي 4 بايت, لماذا؟؟؟؟

و هل في ردي السابق, النتيجة التي ظهرت لي ليست هي المتوقعه؟؟

#9
اقتباس
لم يعمل على VS 2008, لذا قمت بالتعديل

الكود الذى كتبته هو Cpp و ليس C. انا احب استخدام دوال C فهى خفيفه عن كائنات Cpp.

اقتباس
و هو يعطي 4 بايت, لماذا؟؟؟؟

يقوم المترجم بوضع بايت فى اخر الـ structure يسمى بـ padding byte و يستخدم لجعل المساحه المستهلكه منه قابله لعملية الـ align داخل الذاكره.

ألم ترى من قبل أكواد تم تعريف بها متغير بالإسم padding او dummy و لا يتم استخدامه ؟؟

اقتباس
و هل في ردي السابق, النتيجة التي ظهرت لي ليست هي المتوقعه؟؟

المتغيرات و الكائنات يتم عمل align لها داخل الذاكره بمساحات وهى 2، 4، 8، 16، 32 و 64 بايت و هذا يعنى عند تطبيق المعامل and بين اى من الأرقام السابقه (مطروحا منه 1) و المؤشر إذا كان الناتج صفر فالمؤشر هو aligned لهذه المساحه و غير ذلك هو غير aligned لها، أنظر الكود التالى: (الكود هذه المره بلغة الـ C)

#include <stdio.h>
#include <malloc.h>

typedef unsigned char BOOL;
#define TRUE  1
#define FALSE 0

#define SAY(i) (i == 0? "No": "Yes")

BOOL isAligned( void* ptr, int size );


int main()
{
	char* ptr = (char*)malloc(1024);

	printf("is ptr aligned to %i bytes %s.\n", 2, SAY( isAligned(ptr, 2) ) );

	printf("is ptr aligned to %i bytes %s.\n", 4, SAY( isAligned(ptr, 4) ) );

	printf("is ptr aligned to %i bytes %s.\n", 8, SAY( isAligned(ptr, 8) ) );

	printf("is ptr aligned to %i bytes %s.\n", 16, SAY( isAligned(ptr, 16) ) );

	printf("is ptr aligned to %i bytes %s.\n", 32, SAY( isAligned(ptr, 32) ) );

	printf("is ptr aligned to %i bytes %s.\n", 64, SAY( isAligned(ptr, 64) ) );

	free(ptr);

	getchar();
}

BOOL isAligned( void* ptr, int size )
{
	if (size > 64 || (size % 2) != 0) return FALSE;

	return (((unsigned int)ptr) & (size-1)) == 0;
}

الكود الذى كتبته فى مشاركتك السابقه يتم عمل align له بشكل تلقائى من المترجم.

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

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

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