Изисква ли се поведението, дефинирано от внедряването, да бъде последователно между изпълненията в C++?

Позволено ли е на отговаряща на стандарта реализация на C++ да реализира някакво поведение, за което се казва, че е дефинирано от реализация в стандарта по такъв начин, че да е различно между различните изпълнения на една и съща компилирана веднъж програма със същите входни данни?

Например, позволено ли е на внедряване да каже „поведението е това през уикендите и онова в противен случай“ и да приложи поведение според такова изявление?


person sharptooth    schedule 21.07.2010    source източник
comment
имаш ли предвид конкретен пример? алтернативно бих взел внедряване, дефинирано като означаващо точно това и ако внедрителят гарантира последователност, очаквайте последователност, в противен случай всички залози са изключени   -  person msw    schedule 21.07.2010
comment
GCC беше много по-готин с недефинирано поведение: en.wikipedia.org/wiki/Undefined_behavior#Compiler_easter_eggs   -  person sarnold    schedule 21.07.2010


Отговори (6)


Разбира се, ако изпълнението документира кога точно поведението се променя с различни изпълнения, това е добре. Забележете, че дефинираното от внедряването поведение е част от параметрите на абстрактната машина:

Семантичните описания в този международен стандарт дефинират параметризирана недетерминирана абстрактна машина.

Някои аспекти и операции на абстрактната машина са описани в този международен стандарт като дефинирани от изпълнението (например sizeof(int)). Те представляват параметрите на абстрактната машина. Всяко изпълнение трябва да включва документация, описваща неговите характеристики и поведение в тези отношения. Такава документация трябва да дефинира екземпляра на абстрактната машина, който съответства на тази реализация (наричан по-долу „съответстващ екземпляр“).

Това не позволява промяна на поведението в едно изпълнение на компилатора. Но между различните изпълнения на компилатора, компилаторът може да използва различна съответна абстрактна машина, която се различава по различни стойности, дефинирани за изпълнение, според това, което е дефинирало изпълнението. Параметри на командния ред като -Wall (който променя дефинирания от внедряването набор от диагностични съобщения) са най-честият пример за това. Това е разлика спрямо неопределеното поведение в допълнение към изискванията за документация. Неопределеното поведение е много по-малко ограничаващо:

Някои други аспекти и операции на абстрактната машина са описани в този международен стандарт като неуточнени (например ред на оценка на аргументите на функция). Когато е възможно, този международен стандарт определя набор от допустими поведения. Те определят недетерминистичните аспекти на абстрактната машина. Следователно екземпляр на абстрактната машина може да има повече от една възможна последователност на изпълнение за дадена програма и даден вход.

person Johannes Schaub - litb    schedule 21.07.2010
comment
...define a parameterized nondeterministic abstract machine. Тъй като абстрактната машина е недетерминирана, как е необходимо поведението да бъде последователно в едно изпълнение на компилатора? - person Prasoon Saurav; 21.07.2010
comment
@Prasoon, само някои пътища - тези, при които поведението е неуточнено - въвеждат недетерминизъм. Например, регулярният израз z(a|b) може да бъде изразен чрез недетерминиран краен автомат (NFA), който съответства на a или b в края на входа. Но все пак, той постоянно съвпада с z в началото на въвеждането :) Сега за поведение, дефинирано от имплементацията, ако параметрите (да речем, z в началото) се променят, ще получите различна съответна абстрактна машина в резултат. Вече няма да имате една реализация, която превежда изходния код, а две. :) - person Johannes Schaub - litb; 21.07.2010
comment
А!! И въпросът на sharptooth споменава, че входните данни се изискват да бъдат same....Фу! благодаря Йоханес :) - person Prasoon Saurav; 21.07.2010

Един пример, за който мога да се сетя, е дали програмата използва голямо или малко endian представяне за числа. Вярвам, че това със сигурност ще се счита за поведение, определено от изпълнението.

На някои чипове, например някои ARM чипове, е възможно да се превключват режимите по време на изпълнение, така че може да искате компилатор, който може да създаде програма, която да работи в който и да е от двата режима, което означава, че имате дефинирано поведение за изпълнение, което потенциално може да бъде различно при всяко изпълнение в зависимост на външни настройки.

По подобен начин предполагам, че бихте могли да напишете компилатор, който произвежда и 32 и 64 бита, компилирани от една и съща програма - и режимът, който изпълнява, може да бъде определен по време на изпълнение. Отново в документацията трябва да се каже, че int-ите са 32-битови или 64-битови в зависимост от това как сте го стартирали.

Честно казано, не виждам някой да прави нито едно от тези неща, но и двете звучат смътно правдоподобни примери за това, което искахте, и не виждам защо не биха били законни според стандарта, стига документацията да е подходяща документира естеството на зависимото от системата поведение.

person jcoder    schedule 21.07.2010
comment
+1, В MacOSX универсалните двоични файлове съдържат както 32, така и 64-битова версия (в най-новите версии на MacOS X, които имат 64-битова поддръжка) и можете да изберете при стартиране коя версия искате да стартирате. Двоичните файлове могат дори да съдържат код за напълно различна архитектура като PowerPC. И ако се чудите, това е полезно. Има някои плъгини за сафари, които не работят в 64 бита, така че можете да започнете сесия на сафари в 32 бита, когато имате нужда от тях. - person David Rodríguez - dribeas; 21.07.2010
comment
О, хубаво, не знаех, че MaxOSX прави това :) - person jcoder; 21.07.2010

Внедряването на определено поведение означава

Неуточнено поведение, при което всяко внедряване документира как е направен изборът

За авторите на компилатора е задължително да документират поведението на конкретна програмна конструкция за конкретна реализация.

.....по такъв начин, че да е различно между различните изпълнения на една и съща компилирана веднъж програма с едни и същи входни данни?

не!

Например, позволено ли е на внедряване да каже „поведението е това през уикендите и онова в противен случай“ и да приложи поведение според такова изявление?

Не съм сигурен, но мисля, че отговорът е не.

person Prasoon Saurav    schedule 21.07.2010
comment
Не виждам защо това не е разрешено. Стандартът казва как се прави изборът, а не кой избор е направен. - person sharptooth; 21.07.2010
comment
Както виждам, дадената дефиниция на поведение, дефинирано от изпълнението, не изключва възможността за разлики между изпълнение, при условие че документира точно кога възниква всеки случай и точно какво се случва за всеки един. - person j_random_hacker; 21.07.2010
comment
@sharptooth: Редактирах отговора си, но съм почти сигурен, че отговорът на първия ви въпрос е НЕ. Например като се има предвид sizeof(int), гарантирано е (тъй като изпълнението е документирало поведението) да остане фиксирано за конкретно изпълнение. .... малко съм объркан от and implement behavior according to such statement? - person Prasoon Saurav; 21.07.2010
comment
Съответстващо изпълнение може доста лесно да заяви, че sizeof(int) е 4 през делничните дни и 2 през почивните дни. Не е по-различно от заявяването, че ще бъде 2, ако дефинирате INT_IS_2_BYTES или 4 в противен случай. Щом е документирано, всичко е наред. И твърдението 4 през делничните дни, 2 в противен случай е напълно последователно - числата не трябва да са последователни, само спецификация. Разбира се, след като казах това, бих се отклонил от компилатор, който наистина направи това :-) - person paxdiablo; 21.07.2010
comment
Мисля, че трябва да изясните, когато подозирате промяната. Поведението няма да се промени между 2 изпълнения на компилираната програма. Може обаче да се промени, ако компилирате програма два пъти (напр. с различни настройки на компилатора). - person Tobias Langner; 21.07.2010
comment
@paxdiablo: А! Затова казах, че не съм сигурен в отговора на втория му въпрос :). Но все пак не разбирам отговора на Йоханес на първия въпрос. Вижте коментара ми под поста му. - person Prasoon Saurav; 21.07.2010
comment
@paxdiablo: Бих казал, че това ще съответства на формулировката, но не и на намерението на стандарта. - person peterchen; 21.07.2010
comment
@paxdiablo: Може ли компилатор законно да посочи, че „unsigned int“ в паметта е 16 бита, но при определени обстоятелства, при отсъствието на typecasts, междинните изчисления с „unsigned int“ няма да бъдат по-дълги? напр. може ли компилаторът да посочи, че (ui1 + ui2) ›› 1 ще даде аритметично правилна закръглена средна стойност? Мисля, че може за "int", но може ли за "unsigned int"? - person supercat; 01.10.2010

IIRC, system() трябва да съществува, но при дадено изпълнение дефинирано поведение. Нещо като system("ls | grep foo") естествено ще има различни ефекти въз основа на това дали вашата система може или не може да изпълни нещо, наречено ls, което може да варира между изпълненията. И дори на сравнително нормална UNIX машина, където ls и grep правят това, което бихте очаквали и не се изваждат, резултатът пак ще зависи от съществуването на файл с foo в името, което със сигурност ще бъде позволено да варира време и откъде се изпълнява програмата и т.н. Просто зависи от това къде теглите линията на "едни и същи входни данни." Ако машината е в съвършено идентично състояние, тогава можете да очаквате идентично поведение, но няма две изпълнения, които да включват машина в наистина педантично идентично състояние. (Дори температурата на процесора в иначе напълно идентични машини може да доведе до известно поведение на дроселиране, което променя победителя в някакво състезателно състояние, което видимо води до различно поведение на вашата програма.)

person wrosecrans    schedule 21.07.2010

Гаранциите са това, което компилаторът е документирал. Различните флагове на компилатора или различното състояние на компютъра по време на компилиране могат да повлияят на това как компилаторът/оптимизаторът обработва вашата програма и това може да има ефект върху резултата. С флаговете на компилатора, които имат най-голямо въздействие (един и същ компилатор може да се използва за генериране на 32 и 64-битови програми в 64-битова среда, при двата цикъла изискванията за подравняване могат да се различават).

Можете да очаквате, че в повечето случаи имплементаторът ще предостави някои основни гаранции за поведението на имплементацията и програмата, която генерира за даден набор от параметри на компилатор/линкер. Дори ако натоварването на системата може да повлияе на това колко оптимизаторът може да работи върху вашата програма --на някои оптимизатори ще бъде разпределено известно време-- това не трябва да променя очакваното поведение.

Имайте предвид, че въпреки че няма гаранция, би било трудно да се пусне на пазара компилатор, който произвежда код с различно поведение в зависимост от несвързани параметри като позицията на луната спрямо звездите.

person David Rodríguez - dribeas    schedule 21.07.2010

rand(3) в <stdlib.h> може да се извика от C++, не съм сигурен каква част от C библиотеката е включена в "стандартния C++", но със сигурност има някакъв отговарящ на стандартите механизъм за генериране на произволни числа.

time(3) в <time.h> връща текущия час; същата история с C++ и извикване на C библиотеката.

person sarnold    schedule 21.07.2010
comment
как това е свързано с въпроса? - person Naveen; 21.07.2010
comment
rand() или time() означени ли са с дефинирано изпълнение? Мога само да предполагам, че са и ако е така, те наистина биха били контрапример. Е, освен ако не считате текущото време и/или системното RNG състояние за част от входа. - person j_random_hacker; 21.07.2010
comment
@naveen, предположих, че rand() е посочено в стандарта, но подробностите са дефинирани от изпълнението. Имам проблеми с потвърждаването на това предположение. - person sarnold; 21.07.2010