Вы находитесь на странице: 1из 20

СТАНДАРТ С++

Часть первая: введение в стандарт

К. Владимиров, Intel, 2020


mail-to: konstantin.vladimirov@gmail.com
#define r(R) R"()"
/*[*/#include /**/<stdio.h>
#include<math.h>/*!![crc=0f527cd2]*/
float I,bu,k,i,F,u,U,K,O;char o[5200];int
#define R(U) (sizeof('U')==1||sizeof(U"1"[0])==1)
h=0,t=-1,m=80,n=26,d,g,p=0,q=0,v=0,y=112,x=40; float
N(float/*x*/_){g=1<<30;d=-~d*1103515245&--g;return d*_
/g;}void/**/w(int/**/_){if(t<0){for(g=0;g<5200;o[g++ ]=
0);for(;g;o[g+79]=10)g-=80;for(t=37;g<62;o[80+g++]=32) ;
}if(m&&o[h*80+m-1]==10){for(g=0;g<79;o[t*80+g++]=0){}o[t
++*80+g]=10;t%=64;n+=2;I=N(70)+5;if(n>30&&(I-x)*(I-x)+n*
n>1600&&R()){O=0;F=(x=0x1!=sizeof(' '))?k=1+N(2),i=12-k+N(
8),N(4):(k=17+N(5),i=0,r()[0]?O=.1: 0);for(u=U=-.05;u<32;
U=k+i+i*.5*sin((u+=.05)+F))for( K=0 ;K< U;K+=.1)if((bu=K*
sin(u/5),g=I+cos( u/5) *K)>=0&&g < 79 )o[g+(int)(t+44+
bu*(.5-(bu>0?3*O: O) ) )%64* 80 ] =32;x*=02//* */2
-1;n=O+x?n=I+(x?0 :N (k)- k /2),g=(t+42 )%
64,m=-~g%64,x?g=m =-~ m%64:0 ,n>5?o[g*80 +
n-3]=o[m*80+n-3]= 0: 0 ,n <75?o[g*80+n
+2]=o[m*80+n+2]=0 :0:0; x=I;}h=-~h%64
;m=0;}putchar((g=o [h* 80+m++])?g:_);
if(g){w(_);}}void W (const char*_
){for(;*_;w(*_++));} int main(int a
,char**_){while(a--)d +=_[a ]-(char*)0;W( \
"#include<stdio.h>typed" "e" "f\40int\40O;v"
"oid o(O _){putchar(_);}O" "\40main(){O" ""
"*_[512],**p=_,**d,b,q;for(b=0;b" "++<512;p=_+q)_[q" \
"=(p-_+1)*9%512]=(O*)p;") ; for(;(g= getchar())-EOF;p=
q){q=p;for(v=512;p-q-g&&q-p- g; v--)q=-~q*9%512
;W("o(");if(p>q)w(y),w(45);w( 40);w(y^=20
);w(075);for(a=0;a<v;a++)w(42); for(W("(O**"
);a--;w(42)){}w(41);w(y^024);w( 41);if(p<=q)w(
45),w(y^20);W(");");}for(a=7;a-6 ;W(a<6?"{;}":""
))for(a =0;a <6 && !o[h*80+m +a];a++){}W("r"
"etu" /*J */ "rn+0;}\n" );return
/* "#*/0 ;} (c) http://uguu.org/src_fuuko_c.html
Небольшой опыт стандартизации
• Язык INC содержит четыре переменных: a, b, c, d, символы +, post ++, = и ; а
также константа 0. Каждую можно инкрементировать и складывать с
другими. В каждую можно писать результат
• Каждая запись в переменную d это вывод на экран
a = 0; b = a++; c = a + b++ + a; d = c; // на экране 4
• Как вы охарактеризуете следующие программы?
(1) x = 0; (4) a = a++;
(2) a = b++c; (5) a = 0; b = a++ + a++ + a++; d = a + b;
(3) 0 = a; (6) a = 0; c = b = a++; c = a; d = c;

3
Задача которую решает компилятор
• Есть операционная семантика языка
a = b++; // запиши в a значение b, увеличь b на один
• Есть возможности реальной аппаратуры
mov r1, r0; // запиши в r1 значение r0
inc r0; // увеличь r0 на 1
• Они не всегда точно совпадают
• Компилятор должен пересказать программу в терминах вычислительного
устройства, сохранив ожидаемое поведение и выполнив оптимизации

4 https://godbolt.org/z/crdKKx
Стандарт языка
• Язык программирования это соглашение между программистом и
разработчиком компилятора
• Как таковое, оно задокументировано в стандарте языка
• Именно стандарт, а не конкретная реализация является последним и решающим
аргументом в вопросе о том, какая программа компилируется и исполняется
верно, какая нет
• Действующий стандарт C++ это ISO/IEC 14882-2017, принятый в 2017 году
International Organization for Standardization (ISO)
• Подробная информация доступна на
https://isocpp.org/std/the-standard
Нормативные ссылки
• От редакции к редакции абсолютные номера разделов могут плыть
• C++17 overloading это 16-я глава
• С++20 draft overloading это 12-я глава
• Поэтому в стандарте есть символические ссылки. В обоих этих документах
раздел помечен как [over] а разделы С++17, 16.1 или C++20, 12.2 как
[over.load]
• Обычный вид ссылки это [С++17, over] или просто [over] если стандарт не
важен или если имеется в виду последний или если и так всё ясно

6 https://en.cppreference.com/w/cpp/links
Синтаксис и семантика
• Стандарт языка это список диагностируемых правил
• Правила бывают синтаксические (которые можно проверить в грамматике)
template<int i = 3 < 4> struct S; // syntax violation
• И семантические, которые иногда сложно проверить
int foo(int); // foo должна быть где-то определена
int bar(int x) { return foo(x); }
• Реализация, удовлетворяющая стандарту, в идеале должна транслировать и
корректно выполнить программу либо выдать диагностику

7
Well-formed и ill-formed
• Лексически и синтаксически корректные программы делятся на корректные
(well-formed) и некорректные (ill-formed)
int main() {
72057594037927936; // well-formed
}
int main() {
461168601842738790400; // ill-formed [lex.icon]
}

8 https://godbolt.org/z/1fMbfv
Опасность тихих ill-formed программ
• Компилятор не обязан отвергать ill-formed программу
constexpr void g(bool b) { if (b) throw; }
// ill-formed, no diagnostic required by [dcl.constexpr]
constexpr void f() { g(true); }
• [intro.compliance] if a program contains a violation of a rule for which no
diagnostic is required, this document places no requirement on implementations
with respect to that program
• Это очень мрачный угол стандарта. По сути тут мы расписываемся в
неспособности достаточно рано обнаружить фатальную ошибку

9
Расширения
• Компилятор с расширениями может принять и розовую лошадь
• [intro.compliance] A conforming implementation may have
extensions [...]. Implementations are required to diagnose
programs that use such extensions that are ill-formed
according to this International Standard. Having done so,
however, they can compile and execute such programs
• У нас будет отдельный разговор про популярные расширения

10
Любая кухарка может [...]
• Зачем нужны well-formed программы?
• Потому что относительно них обещана предсказуемая семантика
• [intro.abstract] A conforming implementation executing a well-formed program
shall produce the same observable behavior as one of the possible executions of
the corresponding instance of the abstract machine with the same program and
the same input. However, if [...]
• Но там есть одно но скрытое за троеточием
• Сводящееся к "однако это не всегда так"

11
Поведение программ
• Синтаксически некорректные
• Синтаксически корректные
• well-formed (в дальнейшем просто "программы")
• strictly conforming behavior (в стандарте C++ этого нет)
• implementation-defined, locale-specific and conditionally supported behavior
• unspecified behavior
• undefined behavior
• ill-formed
• no diagnostics required

12
Implementation defined
• Мой любимый пример программы с implementation-defined behavior
#include <iostream>
int main() {
std::cout << sizeof(char16_t) << std::endl;
}
• На основании [expr.sizeof] вывод зависит от реализации и однозначен для
этой реализации
• А вы ждали там двойку да?

13
Locale specific
• Введено в основном для новых возможностей форматирования
std::string s3 = std::format("{:L}", 1234);
std::cout << s3 << std::endl; // locale-specific
• Пока что std::format нигде особо не поддержан, но мы очень ждём

14
Conditionally supported
• Всякие мрачные вещи которые по стандарту никто не обязан поддерживать
• Но зачем-то они там всё же упомянуты
asm ("movl %eax, %edi"); // conditionally supported [dcl.asm]
• Ещё пример:
struct S {
int x, y;
virtual ~S() = default;
};
std::cout << offsetof(S, x) << std::endl;

15 https://godbolt.org/z/8YKnfM
Unspecified
• Корректная ситуация в которой может быть несколько равноправных
вариантов выполнения (зависящих от реализации)
• [lex.string] whether successive evaluations of a string-literal yield the same or a
different object is unspecified
• То есть у нас есть два вполне корректных поведения
if ("abc" == "abc") {
// option 1
} else {
// option 2
}

16 https://godbolt.org/z/h7Gv6c
Undefined
• Поведение, не регламентируемое стандартом
unsigned char x = 12;
{ unsigned char x = x; }
• Эта программа синтаксически корректна и well-formed
• Увы, операционная семантика инициализации переменной x внутри scope не
определена стандартом [basic.scope.pdecl]
• Технически это означает, что вместо инициализации компилятор может
вставить туда любую операцию

17
Undefined
• Поведение, не регламентируемое стандартом
• [intro.abstract] A conforming implementation executing a well-formed program
shall produce the same observable behavior as one of the possible executions of
the corresponding instance of the abstract machine with the same program and
the same input. However, if any such execution contains an undefined operation,
this document places no requirement on the implementation executing that
program with that input
• И вот теперь непонятно: чем же отличается well-formed программа с UB
внутри от ill-formed программы?

18
Гуманитарная ремарка
• Мы ещё на этом остановимся много раз, но стандарт языка C++ написан на
естественном языке
• Это означает, что его нельзя читать, прикидываясь роботом. Он написан
людьми и для людей
• У стандарта есть история, есть экзегетика и есть своего рода философия
• В примере с ill-formed vs undefined легко запутаться, но чисто по человечески
всё ясно: ill-formed это вообще не программа на C++, а UB это возможность
соптимизировать код

19
Немного о важности стандартизации
• Тем не менее конкретные формулировки в стандарте очень важны
• Пример: знаменитая memmove/memcpy saga когда внезапно оказалось, что
ядро Линукс много лет закладывалось на некорректное понимание memcpy
• Стандарт это контракт
• Констракты пишутся людьми и для людей, но содержание их пунктов и даже
мелкий шрифт имеют значение

20 https://sourceware.org/bugzilla/show_bug.cgi?id=12518

Вам также может понравиться