فهم تقييم التعبيرات التي تحتوي على المشغلين "++" و "->" في ج

StackOverflow https://stackoverflow.com/questions/776512

سؤال

النظر في هذا المثال:

struct {
    int num;
} s, *ps;

s.num = 0;
ps = &s;
++ps->num;

printf("%d", s.num); /* Prints 1 */

يطبع 1.
لذلك أنا أفهم أنه بسبب الأسبقية للمشغلين، -> أعلى من ذلك ++, ، وبالتالي فإن القيمة ps->num (وهو 0) جلبت أولا ثم ++ يعمل المشغل عليه، لذلك يزيد من ذلك إلى 1.

struct {
    int num;
} s, *ps;

s.num = 0;
ps = &s;
ps++->num;

printf("%d", s.num); /* Prints 0 */

في هذا المثال أحصل 0 وأنا لا أفهم لماذا؛ يجب أن يكون شرح المثال الأول هو نفسه لهذا المثال. لكنه يبدو أن هذا التعبير يتم تقييمه على النحو التالي:
في البداية، المشغل ++ يعمل، ويعمل على ps, ، لذلك يزيد ذلك إلى التالي struct. وبعد حينها فقط -> يعمل ولا يفعل شيئا لأنه يجلب فقط num مجال المقبل struct ولا يفعل شيئا معها.
لكنه يتناقض مع أسبقية المشغلين الذين يقولون ذلك -> لها أسبقية أعلى من ++.

يمكن للشخص أن يفسر هذا السلوك؟

يحرر:
بعد قراءة إجابتين تشير إلى جداول الأسبقية C ++ تشير إلى أن بادئة ++/-- المشغلون لديهم الأسبقية الأقل من ->, ، فعلت بعض googling وتوصلت مع هذا حلقة الوصل ينص أن هذه القاعدة تنطبق أيضا على C نفسه. يناسب تماما وهذا السلوك تماما، ولكن يجب أن أضيف أن الجدول في هذا الرابط يتناقض مع جدول في نسختي الخاصة من K & R ansi C. لذلك إذا كان لديك اقتراحات فيما يتعلق بالمصدر المناسب لأود أن أعرف.

شكرا.

هل كانت مفيدة؟

المحلول

بعد الزيادة (ps++) وزيادة ما قبل (++ps) لديهم ارتباطية مختلفة في C. الشركاء السابقين اليسار إلى اليمين في حين أن الشركاء الأخير في اليسار إلى اليسار. يفحص هذه صفحة خارج (على الرغم من أن هذا هو ل C ++، لذلك قد تكون الأسوحة مضللة).

في مثالك الأخير، تقوم بتغيير المؤشر إلى ماضي واحد في نهاية &s. وبعد لم تغير قيمة المؤشرات. إذا كنت بحاجة إلى زيادة num, ، تحتاج إلى ربط ++ ل num.

شرح مفصل:

 ps++->num;

مترجم (افتراضي) على رؤية هذا التعبير، قد يدفع ps الاعتراض على المكدس تليها ++ المشغل، و -> المشغل وأخيرا الكائن - num. وبعد أثناء تقييم، أين يجب أن يبدأ التحويل البرمجي؟ ينظر إلى المشغلين المتاحة IE ++ و ->. وبعد هل يختار ذلك ps++ أو psب هنا قواعد الأسبقية: منذ -> لديه أسبقية أعلى من ++, ، تستغرق -> لمعالجة مع num كما معامل واحد و ps كما المعامل الأخرى. لذلك، تصبح قيمة التعبير ps->num أي 0 كما تراقب بحق. ما يحدث ل ps بعد التقييم؟ تذكر، هناك مشغل آخر غادر على المكدس؟ لذلك، فإن المحول البرمجي ينطبق هذا على ps ويتوجه الآن إلى عنصر واحد &s.

هامش:

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

نصائح أخرى

حتى إذا كان ++ أولوية أعلى، فلن يغير هذا القيم -> يعمل على ذلك، لأنها زيادة بعد الزيادة. انظر هذا الرمز الذي يحتوي أيضا على مثال آخر على هذا السلوك:

int b = 5;
int a = b++ * 3;
b = 5;
int c = (b++) * 3;

printf("%i, %i, %i\n", a, b, c); // Prints 15, 6, 15

struct {
  int num;
} s, *ps;

s.num = 35;
ps = &s;
printf("%p\n", ps); // Prints the pointer
printf("%i\n", ps++->num); // Prints 35
printf("%p\n", ps); // Prints the increased pointer

printf("%d\n", s.num); /* Prints 35 */

ب = ++ أ؛ أي ما يعادل:

a += 1;
b = a;

ب = ++؛ أي ما يعادل:

b = a;
a += 1;

لذلك من الواضح جدا لماذا لا تحصل على النتيجة التي تبحث عنها. سيكون الشيء الذي وصفته بما يعادل (++ PS) -> Num.

"الأسبقية" هي أساسا ممتلكات مشتقة؛ يتبع من قواعد التحليل. ++ PS-> Num يتم تحليله باسم ++ (PS-> Num) / * () يضاف لتوضيح قواعد التحليل * / بينما PS ++ -> لا يمكن تحليل الأسطوانة فقط ك (PS ++) -> Num.

PS ++ -> Num يزيد من المؤشر PS بنسبة 1، ثم يقرأ البيانات داخلها. نظرا لأن PS هو بعد S فقط على المكدس، أعتقد أنه من المرجح أن يشير المؤشر إلى حد ذاته، على الرغم من أن هذا لست متأكدا من ذلك، وهو أمر غير مهم. أساسا البرنامج الأولي كان يفعل ++ (PS-> الأسطوانات) ولكن بدون الأقواس. لتحقيق نفس الشيء ولكن بعد الوصول إلى البيانات، عليك القيام به (PS-> الأسطوانات) ++، أو بدون الأقواس: PS-> Num ++.

وبما أن PS هو مجرد مؤشر، على الرغم من أنك غيرت قيمتها، لا يزال يتبقى كما هو.

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

يفحص هنا. وبعد يحتوي مشغل Postfix على نفس الأولوية مثل دقة المؤشر، ولكن مشغل البادئة له أولوية أقل.

هنا يمكنك أن ترى ذلك ++ كادئة لها أولوية أقل من ->، ولكن كمسابقة، يكون لها نفس الأولوية كما -> ويتم تقييمها من اليسار إلى اليمين، لذلك يتم تنفيذ PS ++ أولا ثم - >>.

تحرير: هذا هو ل C ++، وليس C. لذلك جوابي غير صحيح.

تستخدم الأسبقية لحل التحليل الغامض. ++ps->num يمكن تحليلها ((++ps)->num) أو (++(ps->num)); ؛ الأسبقية النسبية من ++() و -> يحدد أن الأخير هو التحليل الصحيح.

بالنسبة ps++->num, ، هناك تحليل واحد صالح واحد فقط: ((ps++)->num), ، لذلك الأسبقية من المشغلين لا يهم.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top