كلمة ما معنى هذه الشفرة؟ void(* signal(int sig، void(* func)(int)))(int)؛



معنى كلمة title بالعربية (4)

لقد عثرت على هذه الشفرة وفقدت تماما تفسير معناها.

#include <signal.h>
void (*signal(int sig, void (*func)(int)))(int);

ما هو الشرح التفصيلي للشفرة في السطر 2؟

وأنا أعلم أن void و int هي أنواع ، و * func هو مؤشر لوظيفة ، والأقواس المعقوفة هي للأولوية. لكنني ما زلت لا أحصل على (إشارة * ...) ، و (int) ، والشيء كله مجتمعة معا. شكرا على كل الحب والدعم.

ربما كنت أعرف معنى / تأثير هذا الإعلان. ولكن كان عليّ إجراء بعض التجارب الإضافية لمساعدتي في فهم ما يجري ، على النحو التالي:

  1 #include <signal.h>
  2 void (*signal)(int sig, void (*func)(int));
  3 void (*signal)(int);  // then void (signal)(int) again.
  4 //void (*signal(int sig, void (*func)(int)))(int); //break this line into two lines above
  5
  6 int main(){}

في الكود السابق ، كسرت void (*signal(int sig, void (*func)(int)))(int) إلى سطرين. بالنسبة للخط 3 ، جربت كلا من void (*signal)(int) void (signal)(int) ، مع نفس نتيجة الخطأ التي أشارت إلى أنني كنت أحاول إعادة signal :

TestDeclaration.c: 2: error: 'signal' redeclared as different type of symbol /usr/include/signal.h:93: error: declaration of the 'signal' was here
TestDeclaration.c: 3: error: 'signal' redeclared as different type of symbol /usr/include/signal.h:93: error: declaration of the 'signal' was here

الآن ، أنا أعرف أن كلتا التجربتين هي طرق غير صحيحة للإعلان ، لكن لماذا هي غير صحيحة؟ لماذا الطريقة الأصلية للإعلان ليس إعادة تعريف؟


Answer #1

هذا هو أحد الأمثلة الكلاسيكية على كيف يمكن أن تصبح الإعلانات C المعقدة.
لفهم هذا الإعلان ، فإنه عادةً ما يساعد في إدخال الرموز المميزة لـ typedef:

typedef void (*sighandler_t)(int);
sighandler_t signal(int sig, sighandler_t func);

تعلن typedef مؤشر إلى دالة (أخذ معلمة int وإرجاع أي شيء). يمكن الآن رؤية إشارة الدالة كدالة تأخذ معلمتين (int ومؤشر إلى وظيفة) وترجع المؤشر إلى الدالة.

يمكن أيضًا أن يكون هذا مستمدًا من الإعلان الأصلي ، ولكن الأمر يتطلب القليل من التدريب. الطريقة المعتادة هي أن تبدأ عند المعرف الذي يسمي الكيان الخارجي ( signal هذه الحالة):

signal هي ...

ثم تقرأ مباشرة حتى تجد قوس إغلاق غير متطابق أو نهاية الإعلان: void (* signal (int sig, void (*func)(int) )(int)

signal هي وظيفة تأخذ ... العودة ...

يمكنك الآن الاختيار بين تحليل المعلمات أولاً ، أو قيمة الإرجاع أولاً. سأفعل قيمة الإرجاع أولاً. لذلك ، تقرأ إلى الوراء للعثور على الأقواس المفتوحة المطابقة: void ( signal( / ... */ ) ) (int)

`إشارة هي وظيفة أخذ ... العودة إلى مؤشر ...

قراءة ذهابا وإيابا بهذه الطريقة تحصل في مراحل متتالية:

`إشارة هي وظيفة أخذ ... العودة إلى مؤشر (أخذ وظيفة ... العودة ...)

`إشارة هي وظيفة أخذ ... إعادة مؤشر إلى (وظيفة أخذ ... العودة باطل)

`إشارة هي وظيفة تأخذ ... إعادة مؤشر إلى (وظيفة أخذ كثافة العمليات وإرجاع باطل)

`الإشارة هي دالة تأخذ معلمتين: (int) و (مؤشر إلى دالة أخذ int وإرجاع فارغ) ، وإرجاع مؤشر إلى (دالة أخذ int وإرجاع فارغ)


Answer #2

عودة مؤشر إلى وظيفة والتي تأخذ:

  • العدد الصحيح كوسيطة الوسيطة الأولى و
  • مؤشر إلى وظيفة (والتي تأخذ كثافة العمليات وإرجاع فارغة) كوسيطة كوسيطة ثانية.

ويأخذ حجة صحيحة.


Answer #3

ألف ذاكري أنا خلقت منذ سنوات عديدة ، وهو أمر لا يقدر بثمن عند محاولة فهم أنواع معقدة:

Remember these rules for C declares
And precedence never will be in doubt
Start with the Suffix, Proceed with the Prefix
And read both sets from the inside, out.

إلا عندما يغير الأقواس تلك الأسبقية ، بالطبع.

تطبيقه على هذه الحالة:

void (*signal(int sig, void (*func)(int)))(int);

signal is:
  [inside parentheses]
  [suffix ()] a function, whose arguments are
    sig, which is [prefix int] an integer, and
      func, which is:
         [inside parentheses]
           [no suffix within these parens]
           [prefix *] a pointer to
         [suffix ()] a function, whose argument is
           an int
         [no more suffixes]
         [prefix void] and which returns void
         [no more prefixes]
       [no more arguments]
     [prefix *] And which returns a pointer to
     [no more prefixes within these parens]
   [suffix ()] a function, whose argument is
      an int
   [no more suffixes]
   [prefix void] and which returns void.

مع القليل من التدريب ، ستصل إلى النقطة التي يمكنك فيها القيام بكل ذلك على الفور:

"Signal is function, whose arguments are:
    sig, an integer,
    and func, a pointer to a function whose argument is an int and which returns void
... which returns a pointer to a function that takes int as an argument and returns void.

(عذرا عن الخطأ المرة الأولى - أنا خارج الممارسة).

نعم ، هذا التذكر (مع ضمني "باستثناء الأقواس ، بالطبع) يعمل على جميع إعلانات C ، بغض النظر عن مدى اختلاط المؤشرات ، المصفوفات ، والوظائف.

هذه هي مهارة مفيدة حقا عند محاولة معرفة كيفية عمل رمز شخص آخر ... أو حتى معرفة شيء خاص بك لم تره منذ فترة طويلة.

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

إذا وجدت أن التذكر مفيد ، فلا تتردد في ذكره في مكان آخر - فقط أعطني الفضل كمؤلف ، من فضلك.

بالمناسبة ، هناك أيضا أدوات "C Explainer" التي ستحلل c delaractions وتقوم بتحويلها إلى وصف باللغة الإنجليزية لك. تمت تسمية المنجم باسم CEX لأسباب واضحة ، ولكن هناك العديد من الأشياء الأخرى ، ويجب أن تكون قادرًا على العثور على واحد إذا كنت لا ترغب في ارتكاب هذه المهارة إلى أدوات مبللة أو إذا قام شخص ما بتسليمك شيئًا قبيحًا جدًا بالنسبة لك لتتبعه.


Answer #4

هو إعلان دالة أخذ int و مؤشر إلى دالة (أخذ int إرجاع void) وإرجاع مؤشر إلى دالة (أخذ int وإرجاع void).

شرح ، أو دليل للتفسير

يمكنك أن تفسر بمعالجة كل شيء بين قوسين ككيان واحد ثم تعمل داخليا باستخدام قاعدة "التعريف يتبع الاستخدام".

void (* signal (int sig، void (* func) (int))) (int)؛

يبدو الكيان الموجود بين الأقواس وكأنه دالة تأخذ فقرة int و void .

تجريد الجزء الخارجي:

*signal(int sig, void (*func)(int))

لذا ، تأخذ signal بعض المعلمات وتعيد شيئًا يمكن إلغاؤه (بسبب البادئة * ) لتشكيل وظيفة تأخذ void والعودة.

وهذا يعني أن signal هي دالة تعيد المؤشر إلى دالة (أخذ int وإلغاء void ).

النظر في المعلمات يأخذ int (أي sig ) و void (*func)(int) وهو مؤشر دالة (أخذ int وإرجاع void ).





c