Разное поведение - NSDictionary на iPad против iOS Simulator - PullRequest
1 голос
/ 14 апреля 2011
   int a = 0;

   NSDictionary* d = [NSDictionary dictionaryWithObjectsAndKeys:
                      [NSNumber numberWithInt:a], @"A",
                      [NSNumber numberWithInt:a+=1], @"B",
                      [NSNumber numberWithInt:a+=1], @"C",
                      nil];
   NSLog(@"%@", d);

Результат на iPad:

{A = 0;B = 1;С = 2;}

Результат в iOS Simulator:

{A = 2;B = 2;С = 1;}

Может кто-нибудь воспроизвести результат, или даже лучше, объяснить его?

Ответы [ 2 ]

8 голосов
/ 14 апреля 2011

Это неопределенное поведение. Нет правильного ответа на эти значения. Порядок применения эффектов между точками последовательности не определен, а запятые в списке аргументов не являются точками последовательности.

6 голосов
/ 14 апреля 2011

Порядок вычисления аргументов функции или метода не определен и определяется компилятором.Это означает, что нет никакой гарантии, что первое число будет создано до второго, и оно унаследовано target-c от c.Похоже, что на iPad они выполняются в том же порядке, что и в коде, но для симулятора они создаются в обратном порядке.Это порядок событий:

iPad:

  1. Оценить первый аргумент.Это метод.Его аргументы должны быть обработаны:
    1. Аргументом является переменная a.Используйте его текущее значение (0).
  2. Оцените второй аргумент.Это постоянная строка.Загрузите его адрес.
  3. Оцените третий аргумент.Это метод.Его аргументы должны быть обработаны:
    1. Аргумент является выражением: a += 1.Увеличьте a и верните новое значение (1).
  4. Оцените четвертый аргумент.Это постоянная строка.Загрузите его адрес.
  5. Оцените пятый аргумент.Это метод.Его аргументы должны быть обработаны:
    1. Аргумент является выражением: a += 1.Увеличьте a и верните его новое значение (2).
  6. Оцените шестой аргумент.Это постоянная строка.Загрузите его адрес.

Симулятор:

  1. Оцените шестой аргумент.Это постоянная строка.Загрузите его адрес.
  2. Оцените пятый аргумент.Это метод.Его аргументы должны быть обработаны:
    1. Аргумент является выражением: a += 1.Увеличьте a и верните его новое значение (1).
  3. Оцените четвертый аргумент.Это постоянная строка.Загрузите его адрес.
  4. Оцените третий аргумент.Это метод.Его аргументы должны быть обработаны:
    1. Аргумент является выражением: a += 1.Увеличьте a и верните его новое значение (2).
  5. Оцените второй аргумент.Это постоянная строка.Загрузите его адрес.
  6. Оцените первый аргумент.Это метод.Его аргументы должны быть обработаны:
    1. Аргументом является переменная a.Используйте его текущее значение (2).

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

Чтобы исправить ваши проблемы, вы должны создать объекты NSNumber перед созданием словаря, заставляя компилятор использовать нужный вам порядок.

int a = 0;
NSNumber *numA = [[NSNumber alloc] initWithInt:a];
a += 1;
NSNumber *numB = [[NSNumber alloc] initWithInt:a];
a += 1;
NSNumber *numC = [[NSNumber alloc] initWithInt:a];
NSDictionary *d = [NSDictionary dictionaryWithObjectsAndKeys:numA, @"A", numB ,@"B", numC, @"C", nil];
[numA release];
[numB release];
[numC release];
NSLog(@"%@", d);
...