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

كيفية الإدلال على أن الداله لم تنجح

بدأه mhewedy في 8 سبتمبر 2010 · 19 رد · 942 مشاهدة · في لغة C و ++C
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم......

في لغة السي (وليس السي++), كيف أقول أن الداله هذه لم تنجح في عملها؟؟

طبعا لن نفعل التالي:

fprintf(stderr " function failed");

بإعتبار أننا نبرمج libraries وليس برامج لل end-user

مثلا.. هب أن لدي الداله pop الخاصه بال stack ... و أريد أن أقول للمستخدم أنه لم يعد يوجد أي عناصر داخل ال stack , فكيف أعبر له عن ذلك؟

طبعا لن أقوم بإرجاع -1 , لأنها تصح أن تكون عنصر من العناصر.... فكيف يتم عمل ذلك؟

فكرت بأن أجعل errno بأي قيمه أكبر من أو تساوي 200 مثلا ,,, و من ثم بعدما أقوم بإستدعاء الداله pop أقوم بفحص ال errno .... (ممكن مثلا نعمل مجموعه من ال MACROS تقوم بتغليف هذه العمليه).....

فما رأيكم؟

تم تعديل هذه المشاركة بواسطة هويدي في 8 سبتمبر 2010 في 16:05

#2

شيء تعملته عند كتابة Kernel-mode device drivers لنظم NT وهي مكونات حساسة جداً (كما في اي نظام آخر) .

لا تقم أبدا أبدا بارجاع قيمة للمستخدم عن طريق أي دالة ، بل قم بارجاع Status Code تعطي معلومة عن فشل او نجاح الدالة .

NTSTATUS Divide(ULONG X, ULONG Y, PULONG lpResult)
{
	NTSTATUS status = STATUS_SUCCESS;

	__try
	{
    	//
    	// Probe Parameters ...
    	//
    	*lpResult = (X / Y);
	}
	__except(EXCEPTION_EXECUTE_HANDLER)
	{
    	status = GetExceptionCode();
    	*lpResult = 0;
	}

	return status;
}

تم تعديل هذه المشاركة بواسطة GamingMasteR في 8 سبتمبر 2010 في 17:17

1

mov eax, dword ptr ds:[0xffdf0308]

jmp dword ptr [eax+0xfc]

#3

فى هذه الحاله يمكنك تطبيق الفكره المستخدمه فى ويندوز لإرجاع قيمتين من الداله حيث القيمه العائده من الداله دائما تتعلق بحالة التنفيذ و القيمه الثانيه تعود من خلال أخر معامل، إذا كانت الداله نجحت يتم العوده بـ ERROR_SUCCESS أى صفر و غير ذلك يتم العوده برقم يمثل حالة الخطأ.

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

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

#4

هل تقصدون :

status func(in, out);

مم.. لست مرتاح للشكل ...

#5

دائما سابقنى يا G

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

#6

ما رايك ان تجعل هناك متغير global بينهم(وليكن رقم errno ) لتقوم بتغييرة فى حالة الفشل (ووضع رقم يمكن تحويلة لstring يمثل الخطاء) .

اذا اراد المستخدم الكشف عن حدوث خطاء او لا فليفحص هذا المتغير .

name : mohamedyosry

#7
اقتباس
ما رايك ان تجعل هناك متغير global بينهم

Thread-unsafe

mov eax, dword ptr ds:[0xffdf0308]

jmp dword ptr [eax+0xfc]

#8
اقتباس
Thread-unsafe

معلوماتى بسيطة عن الthreading ولكن هذا المفهوم يطبق جزئيا فى errno.h .وثانيا يجب استخدام mutex وما الى ذلك (على حد علمى لعمل thread safe )

name : mohamedyosry

#9

نعم يمكن استخدام Software lock لكن كله على حساب الـPerformance ، فلو لم تكن العملية تستاهل فبرأيي البعد عن الـSoftware locks و الـGlobal variables التي تعرضنا للمخاطرة أفضل smile.gif

mov eax, dword ptr ds:[0xffdf0308]

jmp dword ptr [eax+0xfc]

#11
اقتباس
Thread-unsafe

يوجد حل للتحايل على هذه النقطه و هو أيضا مأخوذ من ويندوز، داخل ويندوز كل thread له مجموعة بيانات مرتبطه به تمثل داخل Thread Environment Block أو أختصارا TEB هذا التركيب أحد عناصره هى ErrorCode و التى تحتوى على أخر رقم خطأ حدث داخل هذا الـ Thread، التحايل الذى أقصده هنا هو عدم استخدم دوال انشاء الـ Threads بشكل مباشر و إنما تغليف ذلك الإستدعاء من داخل دوال أخرى تقوم بهذا الإستدعاء بالإضافة إلى حجز مساحه من الذاكره لهذا الـ Thread و التى يتم تخزين داخلها رقم الخطأ و عندما تستدعى الداله التى تعيد لك رقم الخطأ (أو تضعه) تقوم هى بمعرفة الـ ID الخاص بالـ Thread و من ثم تبحث تقوم بالوصول من خلال هذا الـ ID للمساحه التخزينيه لرقم الخطأ.

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

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

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

#12

اعتقد فى حالة الthreading يتم استدعاء __errno_location() بدلا من تعريفة ك global var

اقتباس
The __errno_location() function shall return the address of the errno variable for the current thread.

لم استطع الوصول للسورس الخاص بها . ولكن باعتقادى ممكنة فى حالة ان تكون reentrant function وتستعمل دالة لمعرفة الthread التى قام بندائها (مثل pthread_self(); )

name : mohamedyosry

#13

كمثال على نقطه TEB التى ذكرتها، أنظر معى هذا المثال البسيط:

typedef __LOCAL_TEB
{
    int  ThreadID;
    int  LastErrorCode;

    LOCAL_TEB* Next;
} LOCAL_TEB;

LOCAL_TEB* teb; // teb is the head element and it ment to main process thread

int CreateThread(.......)
{
    LOCAL_TEB* t = (LOCAL_TEB*) malloc(sizeof(LOCAL_TEB));
    t->ThreadID = OS_CreateThreadMethod(........);
    t->Next = NULL;

    teb->Next = t;
    return t->ThreadID;
}

void DestoryThread(int id)
{
   LOCAL_TEB* cur = teb;
   LOCAL_TEB* prv = NULL;

   OS_DestroyThreadMethod(id);

   do
   {
      if (t->ThreadID == id)
      {
          if (prv != NULL) prv->Next = cur->Next;
          free(cur);
          break;
      }
      prv = cur;
   }
   while( cur = cur->Next )
}


void setLastError(int errorCode)
{
   LOCAL_TEB* t = teb;
   int id = OS_GetCurrentThreadID();

   do
   {
      if (t->ThreadID == id)
      {
          t->LastErrorCode = errorCode;
          break;
      }
   }
   while( t = t->Next )
}

int  getLastError()
{
   LOCAL_TEB* t = teb;
   int id = OS_GetCurrentThreadID();

   do
   {
      if (t->ThreadID == id) break;
   }
   while( t = t->Next )

   return t->LastErrorCode;
}

المفترض داخل الداله main عمل initialize للمتغير teb برقم الـ thread الرئيسى للبرنامج.

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

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

1

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

#14

مازلت أحب استخدام الـstatus code tongue.gif

غير معقدة وسريعة بخلاف اسلوب الـPOSIX wacko.gif

mov eax, dword ptr ds:[0xffdf0308]

jmp dword ptr [eax+0xfc]

#15

الاقتراح الذي قدّمه الاخ GamingMaster أراه كثيراً في Win32 APIs ،

لكن في لغة سي / هناك حلول أخرى مثل وضع أي خطأ في Stack ، حيث كل دالة يحصل فيها الخطأ ، تضعه في Stack الأخطاء ، ومن ثم الوصول لآخر خطأ عن طريق دالة ينشئها صاحب المكتبة مثل getLastError ، وهذا مثلاً تستخدمه OpenGL المكتوبة في لغة سي . المستخدم النهائي عليه أن يستخدم الدالة getLastError بالطريقة التي يريدها .

doSomething();
doAnotherthing();

while(getLastError()!= NO_ERROR)
 // there is an error

و هذا موجود حتى في Win32 APIs حسب ما اذكر ، فهي تمزج بين ما ذكره الأخ GamingMaster و بين GetlastError ، بينما في OpenGL تعتمد فقط على GetLastError ، وهذا يجعل الكود نظيفاً بعض الشيء .

شخصياً لا يعجبني هذا الأسلوب وأميل لأساليب أخرى ، بعضها لا يمكن تطبيقه في لغة سي ، هذا موضوع قد يكون له علاقة وإن كانت ليست قوية :

http://www.arabteam2...howtopic=205374

* ملاحظة : قرأت بعض الردود على عجل ، وأعتذر إن أضفت رد مكرر لم يأتِ بجديد .

logo1.png تطبيق طمأنينة ، نسخة بيتا على أندرويد

عبدالله الشمّري - Al-Shammari

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#16

أعتقد أن الطريقة الصحيحة لإرجاع خطأ هو إستخدام الException

إلا إذا كنت تريد تصميم شئ لReal-time system or high-performance application

لأن هذه الطريقة هي ال Standard

ودي افصل في المسألة لكن المشكلة أني لا أملك كيبورد عربي وكتابة جملة بها كلمة إنجليزية يحتاج إلى مجهود كبير :)

بالنسبة إذا كنت تقصد أنك تريد إرجاع رسالة معينه للمبرمج مع القيمة المرجعة فستطيع عمل مثلما تم عمله في الSTL ... أقصد بالنسبة لحالة الstack فقد تم خلق دالة empty وبالتالي يجب على المبرمج إستدعاء هذه الدالة قبل إستدعاء الدالة pop وقس عليها ...

تم تعديل هذه المشاركة بواسطة b.m.s في 8 سبتمبر 2010 في 20:58

#17

يمكن ارجاع قيمة true في حالة النجاح و False في حالة فشل الدالة.

لكن من الافضل لو تم الاعتماد على ال exeptions لانها تتوفر على مزايا اخرى.

#18

We are talking about pure C

mov eax, dword ptr ds:[0xffdf0308]

jmp dword ptr [eax+0xfc]

#20

لو أن الأمر بـ ++C فسأستخدم الـ Exceptions, و لكن أنت تتكلم عن C. الـ Status Code مع دوال مساعدة لوصف الخطأ نصياً و خلافه, أي يكون لديك نظام مبسط لمعرفة الأخطاء و نصوص تعرف الخطأ إن أرد المبرمج. و هذه هي الطريقة "الأنظف" في C حسب معرفتي. طريقة الـ Error Stack, لا أفضلها و لم أجرب في الحقيقة استخدامها من قبل في C.

أعتقد أنها يمكن أن تكون thread safe لو استخدمنا atomic types على منصات كثيرة. تحتاج إلى أساتذتنا GM و محمد لشرح هذا الأمر :)

تحياتي..

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

عدد الزوار حالياً

المتواجدون خلال آخر دقيقتين · يتحدّث كل ٣٠ ثانية

—الإجمالي—أعضاء مسجّلون—زوار بدون تسجيل

جارٍ التحقق من المتواجدين…