2014-01-06 2 views
6

Программа 1:C эквивалентный оператор создает путаницу

#include<stdio.h> 
void main() 
{ 
    int i=55; 
    printf("%d %d %d %d\n",i==55,i=40,i==40,i>=10); 
} 

Программа 2:

#include<stdio.h> 
void main(){ 
    int i = 55; 
    if(i == 55) { 
     printf("hi"); 
    } 
} 

Первая программа даст выход 0 40 0 1 здесь в printf i == 55 и выход будет 0, а во второй программе тоже i ==55 и выход - привет. почему

+7

у вас есть операция назначения в первом printf !! .. вывод первого кода определяется реализацией. –

ответ

9

В первом примере операторы оцениваются в обратном порядке, потому что они толкаются так же, как в стеке. Порядок оценки является специфичным для реализации, а не определенным стандартом C. Так squence как это:

  1. я = 55 начальное назначение
  2. я> = 10 == верно 1
  3. я == 40 == ложь (это 55) 0
  4. я = 40 назначение 40
  5. я == 55 == лОЖЬ (Это 40) 0

Второй пример должен быть очевиден.

+1

+1. Также зависит от используемых оптимизаций ... – TrueY

3

Здесь аргументы printf оцениваются справа налево (это неуказанное поведение, но поведение, которое вы заметили, показывает, что по крайней мере первый аргумент оценивается после второго). В вашем списке аргументов есть i=40, который устанавливает значение 40. Поэтому первый напечатанный аргумент равен false (0).

+1

Порядок оценки не определен. В основном в зависимости от оптимизации. Значения, помещенные в стек, находятся справа налево. – TrueY

+1

Для установки параметров в стек также является специфичной для реализации. Например, для цели x86-64 'gcc' использует регистры вместо стека. –

+0

@TrueY, тогда вы говорите, что это 'неопределенное поведение' не является« неопределенным поведением » –

2

Причина в том, что порядок, в котором аргументы функции printf (фактически любая функция) оценивается, перед передачей функции не определяется стандартом C.

Проблема не в вашем понимании оператора ==.

Edit: Хотя многие авторы указывают на то, что printf обычно оценивает свои аргументы, справа налево (я не знаю), я бы сказал, что это, вероятно, плохая идея, чтобы написать код, который зависит от это, поскольку язык не гарантирует этого, и это делает код намного менее удобочитаемым. Тем не менее, это хороший факт, чтобы знать, если вы столкнетесь с этим в дикой природе.

2

Функция printf оценивает выражения в конкретном варианте реализации, в этом случае справа налево. Следовательно, выход:

i==55(0),i=40(Assignment),i==40(0),i>=10(1) 
5

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

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

В типичном случае каждый аргумент функции будет оцениваться как отдельное выражение без перемежения между ними.Другими словами, компилятор будет налагать некоторый заказ на оценку, даже если стандарт не требует этого.

В конкретном случае вариационной функции аргументы обычно помещаются в стек справа налево, поэтому первый аргумент (строка формата) будет находиться в верхней части стека. Это облегчает поиск printf строки формата, а затем (на основе этого) извлекает остальные аргументы из дальнейшего стека.

Если (как и довольно), то аргументы вычисляются непосредственно перед тем, как их вставлять в стек, это приведет к тому, что аргументы будут также оцениваться справа налево.

Функции с фиксированным числом аргументов не оцениваются справа налево почти так же часто, поэтому, если (например) вы написали небольшую обертку с фиксированным числом аргументов, которые затем передавали их до printf, есть больше шансов, что i будет иметь значение 55, когда первый аргумент printf вычисляется, так что будет производить 1 вместо 0.

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

+0

Аргументы всегда сдвигаются справа налево. Ничего особенного о prointf или вариационных функциях. – Devolus

+1

@Devolus: Я предлагаю вам прочитать о некоторых различных соглашениях о вызовах (то, что вы утверждаете, просто неверно). Например, компилятор Microsoft поддерживает соглашение о вызове cdecl, которое нажимает налево, а вызывающий очищает стек - но он также поддерживает 'stdcall',' fastcall' и (в C++) 'thiscall', все из которых вызывают аргументы слева направо, и вызывающий очищает стек. –

+0

Вы правы, я просто посмотрел. – Devolus

2

В первой программе: порядок оценки аргументов printf() является определением. Таким образом, эта программа не дает того же результата при различной импликации printf() Таким образом, нет никакой гарантии о том, что приведет программа.

Он может выводить 0 40 0 1, так как он может выводить 1 40 1 1, если порядок оценки изменен.

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