
مراجعات الكود مطلوبة بالتأكيد ومفيدة. هذه فرصة لنقل المعرفة ، والتدريب ، والتحكم في المهمة ، وتحسين جودة وتصميم الكود وإصلاح الأخطاء. علاوة على ذلك ، يمكنك ملاحظة أخطاء عالية المستوى مرتبطة بالعمارة والخوارزميات المستخدمة. بشكل عام ، كل شيء على ما يرام ، لكن الناس يتعبون بسرعة. لذلك ، يعد التحليل الساكن مكملاً ممتازًا للمراجعات ويساعد في الكشف عن مجموعة متنوعة من الأخطاء والأخطاء المطبعية التي لا يمكن ملاحظتها بالعين. دعونا نلقي نظرة على مثال جيد حول هذا الموضوع.
حاول العثور على الخطأ في كود الوظيفة المأخوذ من مكتبة Structopt :
static inline bool is_valid_number(const std::string &input) {
if (is_binary_notation(input) ||
is_hex_notation(input) ||
is_octal_notation(input)) {
return true;
}
if (input.empty()) {
return false;
}
std::size_t i = 0, j = input.length() - 1;
// Handling whitespaces
while (i < input.length() && input[i] == ' ')
i++;
while (input[j] == ' ')
j--;
if (i > j)
return false;
// if string is of length 1 and the only
// character is not a digit
if (i == j && !(input[i] >= '0' && input[i] <= '9'))
return false;
// If the 1st char is not '+', '-', '.' or digit
if (input[i] != '.' && input[i] != '+' && input[i] != '-' &&
!(input[i] >= '0' && input[i] <= '9'))
return false;
// To check if a '.' or 'e' is found in given
// string. We use this flag to make sure that
// either of them appear only once.
bool dot_or_exp = false;
for (; i <= j; i++) {
// If any of the char does not belong to
// {digit, +, -, ., e}
if (input[i] != 'e' && input[i] != '.' &&
input[i] != '+' && input[i] != '-' &&
!(input[i] >= '0' && input[i] <= '9'))
return false;
if (input[i] == '.') {
// checks if the char 'e' has already
// occurred before '.' If yes, return false;.
if (dot_or_exp == true)
return false;
// If '.' is the last character.
if (i + 1 > input.length())
return false;
// if '.' is not followed by a digit.
if (!(input[i + 1] >= '0' && input[i + 1] <= '9'))
return false;
}
else if (input[i] == 'e') {
// set dot_or_exp = 1 when e is encountered.
dot_or_exp = true;
// if there is no digit before 'e'.
if (!(input[i - 1] >= '0' && input[i - 1] <= '9'))
return false;
// If 'e' is the last Character
if (i + 1 > input.length())
return false;
// if e is not followed either by
// '+', '-' or a digit
if (input[i + 1] != '+' && input[i + 1] != '-' &&
(input[i + 1] >= '0' && input[i] <= '9'))
return false;
}
}
/* If the string skips all above cases, then
it is numeric*/
return true;
}
لكي لا تقرأ الإجابة عن طريق الخطأ على الفور ، سأضيف صورة.

لا أعرف ما إذا كنت قد وجدت خطأ أم لا. حتى لو وجدته ، ستوافق بالتأكيد على أنه ليس من السهل العثور على مثل هذا الخطأ المطبعي. علاوة على ذلك ، كنت تعلم أن هناك خطأ في الوظيفة. إذا كنت لا تعرف ، فمن الصعب أن تجعلك تقرأ بعناية وتتحقق من كل هذا الرمز.
في مثل هذه الحالات ، سوف يكمل محلل الكود الثابت مراجعة الكود الكلاسيكية تمامًا. لا يتعب المحلل وسيقوم بفحص الكود بالكامل. نتيجة لذلك ، يلاحظ محلل PVS-Studio وجود شذوذ في هذه الوظيفة ويصدر تحذيرًا:
V560 جزء من التعبير الشرطي دائمًا كاذب: المدخلات [i] <= '9'. Structopt.hpp 1870
بالنسبة لأولئك الذين لم يلاحظوا الخطأ ، سأقدم تفسيرا لذلك. أهم شيء:
else if (input[i] == 'e') {
....
if (input[i + 1] != '+' && input[i + 1] != '-' &&
(input[i + 1] >= '0' && input[i] <= '9'))
return false;
}
يتحقق الشرط أعلاه من أن العنصر i هو الحرف "e". وفقًا لذلك ، إدخال الشيك التالي [i] <= '9' لا معنى له. تكون نتيجة الفحص الثاني خاطئة دائمًا ، وهو ما تحذر منه أداة التحليل الثابت. سبب الخطأ بسيط: أسرع الشخص وختم نفسه ، ناسياً أن يكتب +1.
في الواقع ، اتضح أن الوظيفة لا تكمل مهمتها في التحقق من صحة الأرقام المدخلة. الخيار الصحيح:
else if (input[i] == 'e') {
....
if (input[i + 1] != '+' && input[i + 1] != '-' &&
(input[i + 1] >= '0' && input[i + 1] <= '9'))
return false;
}
ملاحظة مثيرة للاهتمام. يمكن عرض هذا الخطأ على أنه أحد أشكال " تأثير السطر الأخير ". حدث الخطأ في آخر حالة للوظيفة. في النهاية ، تضاءل انتباه المبرمج ، وارتكب هذا الخطأ الدقيق.

إذا أعجبك المقال حول تأثير السطر الأخير ، أوصي بقراءة ملاحظات أخرى مماثلة: 0-1-2 ، memset ، المقارنات .
وداعا للجميع. أنا أحب أولئك الذين وجدوا الخطأ من تلقاء أنفسهم.