Skip to the content.

Фишки


1. Поменять местами значения переменных a и b: swap(a, b);

2. Оператор goto:

goto AFTER_CYCLE;
AFTER_CYCLE:проверка на успешное чтение

3. Минимально возможное число int:

#include <climits> 
int max = INT_MIN;

4. Пустое место

5. if (cin >> n); - проверка на успешное чтение

if (cin >> n && n); - проверка на успешное чтение и на n != 0

6. В С\С++ система ленивого сравнения:

Если первое условие не выполняется (а != 0), то второе даже не будет проверяться

(0 == a && x > 5)

Если первое условие выполняется (а == 0), то второе даже не будет проверяться

(0 == a || x > 5)

7. Операция присваивания (а не оператор, как во многих яп)

В Си вполне допустима такая конструкция:

x = (y=17) + 1; // = 18
a = b = c = d = e + 5; // результат e + 5 будет занесен в d, d в c, c в b, b в a

8. Блок - конструкция для объединения нескольких комманд в одну, так же у блока своя область видимости:

{
    int k = 5;
    i = k + 5;
}
// k за блоком не существует

9. for(;;){} тоже самое что while(true){}

10. do{} while(false) выполнится только 1 раз

11. cin.get(c); считать 1 символ с iostream и положить значение в переменную с

12. Функция system() передает командному процессору операционной системы команду в строке и возвращает статус выхода команды:

system(ls); // тоже самое что написать ls в терминал

13. #include <cstddef> - size_t

14. #include <cstring - работа со C-style строками (strlen, strcpy)

15. Объединения - поля разделяют между собой одну и туже область памяти. Область памяти которую мы можем интерпретировать как int либо как char:

union Un
{
    char c;
    int i;
};

Un un;
un.c = 'a';
// i = 97 
// c = 'a' 

Поля перекрывают друг друга:

int
Байт 1 Байт 2 Байт 3 Байт 4
char

16. Ключевое слово register (убрали в С++17)

Спецификатор register рекомендует компилятору сохранить переменную способом, который позволит осуществлять самый быстрый доступ к ней, чаще всего это в регистре процессора (вместо стандартного хранения в ОЗУ). Так как это только рекомендация, то компилятор может просто её проигнорировать!

register int a;

17. Препроцессорная склейка строк

int ma\
in()
{
    retu\
    rn 0;
}

Конечно можно и не использовать \, однако это является самым правильным способом переноса строки.

Чаще всего используется для красивого оформления макросов:

#define macro\
some\
code

18. Конкатенация строк во время компиляции

std::cout << "Hello" ", world"; склеится в одну строку "Hello, world"

Это удобно использовать когда нужно перенести длинную строку

19. Функции с переменным количеством параметров

В таких функциях хотя бы один параметр обязателен!

Можно было бы передать только один обязательный параметр - количество параметров и полагаясь на знания о том как располагаются параметры на стеке (друг за другом) вывести все остальные параметры:

int * ptr = &count;
std::cout << *ptr << "\n";
std::cout << *(ptr + 1) << "\n";

Однако размещение параметров зависит от компилятора, поэтому такой подход не везде будет работать.

Для упрощение были введены макрокоманды. Все они используют специальный тип va_list, который по сути выступает в качестве указателя на параметры, который перемещают макрокоманды:

#include <stdarg.h> // тут определены макрокоманды

void print(int count, ...)
{
    va_list ptr;
    va_start(ptr, count);
    for (int i = 0; i != count; ++i)
        std::cout << va_arg(ptr, int) << "\n";
    va_end(ptr);
}

print(3, 8, 9, 2); // 8 9 2

20. Макросы с переменным количеством параметров

С макросамы все проще если вспомнить что макрос это просто подстановка текста препроцессором. Соответственно достаточно лишь использовать готовый __VA_ARGS__ что бы подставить все переданные параметры:

#define print(str, ...)\
printf(str, __VA_ARGS__);

print("%d %d %d \n", 2, 3, 4); // 2 3 4

Одно из мощных и одновременно бесполезных применений:

#define for(...) // "обезвредили" все циклы for

21. Порядок исходников при компиляции

Как оказалось порядок, в котором мы передаем исходники важен для компилятора, а точнее это больше важно для линковщика!

Допустим на проекте есть такие файлы:

Собранный фреймворк (.os) лежит тут: ../Framework/tmp/

Заголовок фреймворка лежит тут: ../Framework/inc

Соответственно, команда компиляции должна выглядеть примерно так:

g++ -Wall -I../Framework/inc -L../Framework/tmp/ main.cpp -lFrameworkRelease -lSDL2 -lSDL2_image

Библиотеки (и другие файлы) нужно располагать справа налево, где самая правая менее зависимая от других.

Для красоты можно все ключи и подключаемые библиотеки вынести в отдельные переменные среды:

export FLAGS= -Wall -I../Framework/inc -L../Framework/tmp/
export LIBS= -lFrameworkRelease -lSDL2 -lSDL2_image

Итог:

g++ $(FLAGS) -o game main.cpp ($LIBS)

22. Двойные неравенства

Как известно, особых конструкций для двойных неравенств в Си нет и их нужно оформлять через логические операторы:

(a <= x && x <= b) // xє[a; b]

Однако, если все-таки написать a <= x <= b, то это будет аналогично: (a <= x) <= b. А теперь вспомним что true = 1, false = 0:

int x = 0;
-5 <= x < 1 // ожидаем true
(-5 <= 0) < 1
true < 1
1 < 1 // false!

23. Обмен значений переменных без использования дополнительной переменной

Такой обмен однотипных переменных можно реализовать используя XOR:

int x = 5; // 101
int y = 7; // 111

x = x ^ y; // x = 101 ^ 111 = 010
y = x ^ y; // y = 010 ^ 111 = 101 (5)
x = x ^ y; // x = 010 ^ 101 = 111 (7)

Более короткая запись:

y ^= (x ^= y);
x ^= y;

24. Stack overflow

Интересный пример: что произойдёт?

void f4(char z);

void f3(char x)
{ 
    f4(x);
}

void f4(char z)
{
    f3(z);
}

int main() 
{ 
    f3(126);
    std::cout << "THE END" << std::endl;
}

На самом деле произойдёт переполнение стека, потому что он весь будет забит стековыми фреймами функций

25. static и инстанцирование шаблона

template<class T> 
void Print(T Num) 
{ 
    static int i = 0; 
    std::cout << i++ << std::endl; 
}

int main() 
{ 
    Print(20);    // инстанцирование <int>, выведет 0, i = 1
    Print(2 + 5); // вызов для уже существующего <int>, выведет 1, i = 2
    Print(1.f);   // инстанцирование <float>, выведет 0, i = 1
    Print(1.0);   // инстанцирование <double>, выведет 0, i = 1
    return 0; 
}