2016-12-28 2 views
1

тестирование некоторый код при изучении языка C,C, до и после приращения, разные ответы в разных программах

#include <stdio.h> 
#include <math.h> 
#define hypotenusa(x, y) sqrt((x) * (x) + (y) * (y)) 

int main(void) { 
    int a, x; 
    x = 2; 
    a = hypotenusa(++x, ++x); 
    printf("%d\n", a); 
} 

И я получаю ответ

  • 6 в одной программе (DOSBox компиляторов GCC)
  • 7 в codelight компилятором GCC и
  • 8 на codeChef онлайн компилятор

Может кто-нибудь объяснить это поведение? моя логика говорит, что это должно быть 6 (sqrt(42)), но ...

+1

Также http://stackoverflow.com/questions/11060968/using-the-post-increment-in-function-arguments и многие другие вопросы. – AnT

+0

Извините, я не сразу понял, что это не вызов функции. Однако это не меняет сути проблемы. – AnT

+0

Прочтите информационную страницу, прежде чем спрашивать! Это один из вопросов «не спрашивайте». – Olaf

ответ

6

Это undefined behaviour.

После замены макро

a = hypotenusa(++x, ++x); 

становится:

a = sqrt((++x) * (++x) + (++x) * (++x)); 

Как вы можете видеть x модифицируется несколько раз без какого-либо промежуточного пункта (ов) последовательности. См. What Every C Programmer Should Know About Undefined Behavior.

+1

Стоит отметить, что преобразование его в вызов функции не решит проблему, так как порядок оценки операндов тоже не определен .. –

2

hypotenusa(++x, ++x) - не определено поведение.
Это зависит от компилятора, который из параметров получает приращение (и толкается) первым - после расширения макроса существует всего четыре экземпляра, и последовательность не определена.

Вы не должны увеличивать одну и ту же переменную несколько раз в одном и том же заявлении, чтобы избежать таких проблем. Использование переменной дважды в макросе может скрыть эту ошибку и сделать ее действительно противной.

+0

'hypotenusa' - это макрос, а не вызов функции, и нет ничего плохого в том, приращение переменной во время вызова функции, пока вы увеличиваете ее ТОЛЬКО ОДИН РАЗ. Неисправность возникает, если вы увеличиваете одну и ту же переменную несколько раз. – abelenky

+0

@abelenky, макрос расширяется до вызова функции. Но я уточнил текст, чтобы быть более точным. – Aganju

+0

Не могли бы вы прояснить первый абзац. Это предполагает, что неопределенное поведение приведет к одному из двух возможных результатов, чего не происходит. – 2501

2

Поведение вашего макроса не определено, что означает любой результат возможен.

Chapter and verse

6.5 Выражение
...
        Если побочный эффект на скалярный объекте unsequenced по отношению к любому другому побочному эффекту
            на том же скалярном объекте или в стоимости е вычисление с использованием значения одного и того же скалярного объекта,
            поведение не определено.Если существует несколько допустимых упорядочений подвыражениям
            выражения, поведение не определено, если такая unsequenced сторона эффект возникает в любом
            из упорядочений. 84)
84) Этот пункт оказывает неопределенные выписки такие выражения, как
i = ++i + 1; 
    a[i++] = i; 
           , позволяя
i = i + 1; 
    a[i] = i; 

В принципе, если вы измените значение объекта более одного раза в выражении или оба изменяют объект и используют его значение при вычислении в выражении, результат не будет четко определен, если не существует seq uence point между этими операциями. За некоторыми исключениями, C не приводит к оценке слева или справа от оценок выражений или параметров параметров, а также не требует, чтобы побочный эффект ++ или -- был применен сразу после оценки. Таким образом, результат выражения типа x++ * x++ будет варьироваться от платформы к платформе, программы к программе или даже потенциально от запуска до запуска (хотя я никогда не видел этого на практике).

Например, учитывая выражение y = x++ * x++, следующая последовательность оценки можно:

t0 <- x  // right hand x++, t0 == 2 
t1 <- x  // left hand x++, t1 == 2 
y <- t0 * t1 // y = 2 * 2 == 4 
x <- x + 1  // x == 3 
x <- x + 1  // x == 4 

, который не даст вам результат, который вы ожидаете, если вы предполагаете, слева направо оценки.

Смежные вопросы