2012-02-23 4 views
7

При чтении какого-то вопроса на сайте я наткнулся ниже вопроса, где переменный ток вопрос должен быть отлаживатьКак отлаживать код Этого C

unsigned int a, b, c; 
/* a and b are assume to have some values */ 
c = (a + b)/2; // <- There is a bug in this st 
What is the bug? and how you debug it? 

Некоторые из ответа говоря, что это может вызвать переполнение (с = (а + b)/2). Но действительно не получилось, как это вызывает переполнение?

+0

можете у вас указать ссылку на сайт? – Bazooka

+0

http://geeksforgeeks.org/forum/topic/how-to-debug-the-c-code#post-36549 –

ответ

5

Если a и/или b очень велики, то a + b может превысить максимальный размер целого числа без знака (см MAX_UINT в файле limits.h). Это приведет к переполнению, поэтому результат будет неправильным. Например, если a и b равны 0x80000000, результат будет равен 0 в 32-разрядной арифметике, а не ожидаемый результат 0x80000000.

Чтобы решить эту проблему, вы можете использовать что-то вроде этого, вместо:

c = a/2 + b/2 + (a % 2 == 1 && b % 2 == 1); 

Если вы знаете, что b больше a, то вы можете использовать эту немного более простой вариант:

c = a + (b - a)/2; 

Читать эту статью для получения информации о том, как эта ошибка появилась в бинарных алгоритмах поиска в популярных языках (хотя она говорит о signed int, а не о unsigned int):

+0

@larsmans: Да, статья в основном (но не полностью, если вы внимательно читаете) о Java 'signed int'. Но причина, по которой я включил эту ссылку, была не столько потому, что она напрямую ответила на вопрос (статья не делает этого), но еще и потому, что я думал, что это дает полезный фон для * почему * этот вопрос интересен/уместен и * почему * Знание ответа может быть важным. –

0

Это может вызвать переполнение, если a и b достаточно высоки, чтобы получить a + b выше, чем максимальное представимыми в unsigned int.

8

a+b может вытечь, если сумма a и b больше, чем UINT_MAX, максимальное значение для unsigned int. НАПРИМЕР,

unsigned a = 1; 
unsigned b = UINT_MAX; 

printf("%u\n", (a+b)/2); 

печатает 0.

Если вы хотите, чтобы найти среднее значение двух unsigned int с без перелива, сделать

c = a/2 + b/2 + (a % 2 & b % 2); 

(или (a%2 + b%2)/2 или (a%2 && b%2) или ((a&1) & (b&1)) и т.д.)

+1

Этот ответ заставил меня тоже поднять вопрос. – SashaN

0

Если вы только объявить переменную C без инициализации, он получает непредсказуемое значение. a и b могут быть некоторыми значениями, которые в настоящее время находятся в адресе, который они получают в памяти.

Вы можете отлаживать код С в Eclipse CDT
http://www.eclipse.org/cdt/

С помощью этой IDE можно запрограммировать в C ANC C++ и содержит отладчик GDB.
http://www.gnu.org/software/gdb/

2

Как говорят другие:

unsigned int a, b, c; 
c = (a + b)/2; 

a + b может быть не представима в unsigned int при некотором значении a и b.

Очень похожая ситуация привела к известной ошибке в стандартной реализации двоичного поиска Java (binarySearch).

Посмотреть этот известный блог Джошуа Blosh в 2006 году:

"Extra, Extra - Read All About It: Почти все бинарные запросы и Mergesorts сломаны" http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html

Выдержки:

Ошибка в этой строке:

6: int mid = (низкий + высокий)/2;

дальше:

Так что это лучший способ, чтобы исправить эту ошибку? Вот один из способов:

6: int mid = low + ((high-low)/2);

Обратите внимание, что в Joshua посте, high является >= low, а также int объектов были использованы, но Java трактует подписали переполнение в упаковке. В C-значении целочисленные переполнения являются неопределенным поведением и неподписанным обрывом.

+0

+1 за то, что вы сделали примерно в середине = низкий + ((высокий-низкий)/2) –

+0

@Amit: Я отправил ту же информацию в свой ответ, за исключением того, что я разместил за час до этого. Я также связан с той же статьей, что и этот пост. И я также включил решение самого высокого голосованного ответа (а также до его публикации). Теперь не поймите меня неправильно, я не расстроен, мне просто немного интересно ... почему я тоже не получил от вас выкуп? Был ли мой ответ трудно понять? Вы как-то не видели этого? Пожалуйста, скажите мне, что я сделал не так, чтобы я мог улучшить свои ответы в будущем. –

+0

Эй, @ Марк. Я уже проголосую за вас и очень ценю вашу помощь. –