Первым постом в этом канале станет тот, с которого зародилось название канала.
Долгие разборы "военного синуса" привели меня к квинтессенции проблем, после которых я сумел сконструировать несколько абсолютно отвратительных примеров выстрелов себе в ногу.
Вот такой код, очевидно, не скомпилируется.
Что логично. Мы, конечно, объявили синус от строки, но в глобальном пространстве имен. А вызываем
Но давайте поменяем местами объявление синуса и заголовок
Угадайте что? Правильно: скомпилируется!
А все почему? Правильно, потому что в заголовке cmath (во многих реализациях на linux) есть вот такая строчка:
Будьте осторожны. Она там такая не одна.
Долгие разборы "военного синуса" привели меня к квинтессенции проблем, после которых я сумел сконструировать несколько абсолютно отвратительных примеров выстрелов себе в ногу.
#include <iostream>
#include <cmath>
double sin(std::string x) { return 1.5; }
int main() {
std::cout << "string: " << std::sin(std::string{"0.5"}) << std::endl;
}
Вот такой код, очевидно, не скомпилируется.
<source>:7:40: error: no matching function for call to 'sin(std::string)'
Что логично. Мы, конечно, объявили синус от строки, но в глобальном пространстве имен. А вызываем
std::sin из пространства имен std, и там такого синуса, очевидно, нет.Но давайте поменяем местами объявление синуса и заголовок
cmath. (можем считать, что у нас есть какой-то локальный заголовок, куда такое объявление просочилось)
#include <iostream>
double sin(std::string x) { return 1.5; }
#include <cmath>
int main() {
std::cout << "string: " << std::sin(std::string{"0.5"}) << std::endl;
}
Угадайте что? Правильно: скомпилируется!
Program returned: 0
string: 1.5
А все почему? Правильно, потому что в заголовке cmath (во многих реализациях на linux) есть вот такая строчка:
using ::sin;
Будьте осторожны. Она там такая не одна.
Telegram
this->notes.
#cpp
Ещё есть такой коллега у меня Паша Сухов. Ну как коллега. Он в Доставке вообще работает, но ведь это всё ещё Яндекс. Так что коллега.
Пашу вы могли видеть на C++ Russia:
- Полезные трюки С++ на примере организации пайплайна
- Как заставить шаблоны…
Ещё есть такой коллега у меня Паша Сухов. Ну как коллега. Он в Доставке вообще работает, но ведь это всё ещё Яндекс. Так что коллега.
Пашу вы могли видеть на C++ Russia:
- Полезные трюки С++ на примере организации пайплайна
- Как заставить шаблоны…
😱5🤯3🔥2
Возвращаемся к нашему военному синусу.
Любимый пример, связанный с ним, после которого хочется переехать в комнату с мягкими стенами.
Эта программа нормально скомпилируется, на всех компиляторах, включая icc.
И выводит ожидаемые
Да, мы объявили какой-то синус в глобальном неймспейсе, который выдает какую-то дичь. Но мы вызываем синусы из стандартной библиотеки, значит все должно быть хорошо.
Ну да ладно, давайте ничего не заменим, только закомментируем последнюю строчку.
Что поменяется? Внезапно, поменяется поведение функции в предыдущей строки.
Как так? Почему эта строчка повлияет на поведение предыдущей? А вот, особенности порядка применения оптимизаций icc.
Добро пожаловать к нам в дурку.
Любимый пример, связанный с ним, после которого хочется переехать в комнату с мягкими стенами.
#include <iostream>
#include <cmath>
double
__attribute((weak))
sin(double x) { return 1.5; }
int main() {
std::cout << "double: " << std::sin(double(0.5)) << std::endl;
std::cout << "integer: " << std::sin(int(0)) << std::endl;
}
Эта программа нормально скомпилируется, на всех компиляторах, включая icc.
И выводит ожидаемые
Program returned: 0
double: 0.479426
integer: 0
Да, мы объявили какой-то синус в глобальном неймспейсе, который выдает какую-то дичь. Но мы вызываем синусы из стандартной библиотеки, значит все должно быть хорошо.
Ну да ладно, давайте ничего не заменим, только закомментируем последнюю строчку.
#include <iostream>
#include <cmath>
double
__attribute((weak))
sin(double x) { return 1.5; }
int main() {
std::cout << "double: " << std::sin(double(0.5)) << std::endl;
// std::cout << "integer: " << std::sin(int(0)) << std::endl;
}
Что поменяется? Внезапно, поменяется поведение функции в предыдущей строки.
Program returned: 0
double: 1.5
Как так? Почему эта строчка повлияет на поведение предыдущей? А вот, особенности порядка применения оптимизаций icc.
Добро пожаловать к нам в дурку.
Telegram
this->notes.
#cpp
Ещё есть такой коллега у меня Паша Сухов. Ну как коллега. Он в Доставке вообще работает, но ведь это всё ещё Яндекс. Так что коллега.
Пашу вы могли видеть на C++ Russia:
- Полезные трюки С++ на примере организации пайплайна
- Как заставить шаблоны…
Ещё есть такой коллега у меня Паша Сухов. Ну как коллега. Он в Доставке вообще работает, но ведь это всё ещё Яндекс. Так что коллега.
Пашу вы могли видеть на C++ Russia:
- Полезные трюки С++ на примере организации пайплайна
- Как заставить шаблоны…
😁8🔥5🤬2
Микропостик.
Угадайте, что делает вот такой код?
Вот тут можно посмотреть ответ.
Этот код проверяет, является ли число нечетным.
Вывод
Только способом из дурки.
Угадайте, что делает вот такой код?
union S {
long long int number;
bool yes : sizeof(long long int);
};Вот тут можно посмотреть ответ.
#include <iostream>
union is_odd {
long long int number;
bool yes : sizeof(long long int);
};
int main() {
std::boolalpha(std::cout);
for (long long int i = -10; i < 10; ++i) {
std::cout << i << " is odd? "
<< is_odd{ .number = i }.yes
<< "\n";
}
}
Вывод
-10 is odd? false
-9 is odd? true
-8 is odd? false
-7 is odd? true
-6 is odd? false
-5 is odd? true
-4 is odd? false
-3 is odd? true
...
Только способом из дурки.
😁8❤2
Дисклеймер: я не претендую на невероятною новизну фактов. Я просто показываю всем известные примеры, на которые натыкаюсь раз за разом, раз за разом....
Вот еще один прекрасный пример такой гадости.
Мы сделаем указатели на две переменные. Если ставить оптимизацию до
Внимание, вопрос! Что будет, если мы сравним два одинаковых указателя?
И получаем внезапное:
И на самом деле - никаких противоречий со стандартом. Это просто Unspecified (даже не Undefined) Behavior.
Не буду раскрывать всю подноготную, легко этот пример найти где-нибудь на хабре.
Вопрос другой: вот когда на собеседовании в очередной раз задают вопросы типа "разверни список", или "проверь бинарное дерево на наличие циклов".
Вот что будет, если выдать в ответ собеседующему этот пример, и попросить доказать, что сравнение указателей в случае такого дерева/списка будет вообще работать? Без него же такую задачу не решить?
И посмотреть, как хорошо справится с ответом на этот вопрос тот, кто в очередной раз предложит развернуть список.
Хотя, разумеется, можно написать как-то так
Вот еще один прекрасный пример такой гадости.
#include<iostream>
int main(){
int a, b;
int* p = &a;
int* q = &b + 1;
std::cout << std::hex
<< "p: " << p << "\n"
<< "q: " << q << "\n"
<< std::endl;
}
Мы сделаем указатели на две переменные. Если ставить оптимизацию до
O1 включительно (после O2 начинаются вопросы на gcc) то переменные будут объявлены "по порядку", и это будут одинаковые указатели. Просто сравниваем посимвольно.
clang:
Program returned: 0
p: 0x7ffdfaf2696c
q: 0x7ffdfaf2696c
gcc:
Program returned: 0
p: 0x7ffca3076f0c
q: 0x7ffca3076f0c
Внимание, вопрос! Что будет, если мы сравним два одинаковых указателя?
#include<iostream>
int main(){
int a, b;
int* p = &a;
int* q = &b + 1;
std::cout << std::hex
<< "p: " << p << "\n"
<< "q: " << q << "\n"
<< std::endl;
std::cout << (p == q ? "equal" : "not equal")
<< std::endl;
}
И получаем внезапное:
clang:
Program returned: 0
p: 0x7ffd6bd0d16c
q: 0x7ffd6bd0d16c
equal
gcc:
Program returned: 0
p: 0x7ffe3c48696c
q: 0x7ffe3c48696c
not equal
И на самом деле - никаких противоречий со стандартом. Это просто Unspecified (даже не Undefined) Behavior.
Не буду раскрывать всю подноготную, легко этот пример найти где-нибудь на хабре.
Вопрос другой: вот когда на собеседовании в очередной раз задают вопросы типа "разверни список", или "проверь бинарное дерево на наличие циклов".
Вот что будет, если выдать в ответ собеседующему этот пример, и попросить доказать, что сравнение указателей в случае такого дерева/списка будет вообще работать? Без него же такую задачу не решить?
И посмотреть, как хорошо справится с ответом на этот вопрос тот, кто в очередной раз предложит развернуть список.
Хотя, разумеется, можно написать как-то так
int a, b;
auto p = reinterpret_cast<uintptr_t>(&a);
auto q = reinterpret_cast<uintptr_t>(&b + 1);
std::cout << std::hex << p << "\n" //
<< q << "\n" //
<< std::dec << (p == q) << std::endl; //
godbolt.org
Compiler Explorer - C++
int main(){
int a, b;
int* p = &a;
int* q = &b + 1;
std::cout << std::hex
<< "p: " << p << "\n"
<< "q: " << q << "\n"
<< std::endl;
}
int a, b;
int* p = &a;
int* q = &b + 1;
std::cout << std::hex
<< "p: " << p << "\n"
<< "q: " << q << "\n"
<< std::endl;
}
❤6🔥4🤯4👍1
Микропост.
Что выведет этот код?
Ответ вот тут.
А на самом деле надо бросать монетку, потому что gcc и msvc выведут
А clang и icc выведут
Но вообще, это просто типичный UB. p после реаллока становится невалидным указателем. Из хорошего - gcc это ловит со включенным.
Что выведет этот код?
#include <stdio.h>
#include <stdlib.h>
int main() {
int *p = (int*)malloc(sizeof(int));
int *q = (int*)realloc(p, sizeof(int));
if (p == q) {
*p = 1;
*q = 2;
printf("%d %d\n", *p, *q);
}
}
Ответ вот тут.
Program returned: 0
Program stdout
2 2
А clang и icc выведут
Program returned: 0
Program stdout
1 2
Но вообще, это просто типичный UB. p после реаллока становится невалидным указателем. Из хорошего - gcc это ловит со включенным
Wall😱2💯1
Итак, один из любимых примеров дурки.
Мы заводим структуру данных, которая конструируется от аргумента типа double. И вторую структуру, которая конструируется от первой.
А дальше создадим переменную второго типа.
Проигнорируем ворнинги компиляторов (кого оно волнует, компилируется же).
А что будет, если мы выведем значение перменной
Внезапно, выведет 1:
Чта?!
Ну, пришло время почитать ворнинги. И выясняем, что вот это:
не переменная. Это - функция. Дело в том, что вот два таких объявления функций, в целом, одинаковые:
Мы вполне легально можем аргументы функции заключать в скобки при объявлении функций... А все, что может быть трактовано в С++ как объявление функции, должно быть трактовано как объявление функции.
И.... Я не знаю, как оно так в итоге так получается, но стреляет время от времени...
Добро пожаловать к нам в дурку.
Мы заводим структуру данных, которая конструируется от аргумента типа double. И вторую структуру, которая конструируется от первой.
А дальше создадим переменную второго типа.
#include<iostream>
struct A {
double v;
explicit A(double d) : v(d) {}
};
struct B {
double v;
explicit B(A a) : v(a.v) {}
};
int main(){
double d = 3.14;
B b(A(d));
}
Проигнорируем ворнинги компиляторов (кого оно волнует, компилируется же).
А что будет, если мы выведем значение перменной
b?int main(){
double d = 3.14;
B b(A(d));
std::cout << b << std::endl;
}Внезапно, выведет 1:
Program returned: 0
1
Чта?!
Ну, пришло время почитать ворнинги. И выясняем, что вот это:
B b(A(d));
не переменная. Это - функция. Дело в том, что вот два таких объявления функций, в целом, одинаковые:
void f(int a);
void q(int(a));
Мы вполне легально можем аргументы функции заключать в скобки при объявлении функций... А все, что может быть трактовано в С++ как объявление функции, должно быть трактовано как объявление функции.
И.... Я не знаю, как оно так в итоге так получается, но стреляет время от времени...
Добро пожаловать к нам в дурку.
godbolt.org
Compiler Explorer - C++
struct A {
double v;
explicit A(double d) : v(d) {}
};
struct B {
double v;
explicit B(A a) : v(a.v) {}
};
int main(){
double d = 3.14;
B b(A(d));
}
double v;
explicit A(double d) : v(d) {}
};
struct B {
double v;
explicit B(A a) : v(a.v) {}
};
int main(){
double d = 3.14;
B b(A(d));
}
🤯9❤4
У мну вопрос.
Есть вот такая строчка.
И вот в чем вопрос... В комментарии написано, что мы ждем от 2 до 6 секунд.
В функции мы берем минимум 1000 ms (одна секунда).
Мы берем по модулю 68 (не 60) и получаем 6.8 секунды.
Почему 68? Нахрена вообще понадобилась такая функция?
Столько вопросов... Но в этот раз не к языку. 🤡
Есть вот такая строчка.
// Waits for 2..6 seconds.
void SymbianEngine::updateConfigurationsAfterRandomTime()
{
int iTimeToWait = qMax(1000, (qAbs(qrand()) % 68) * 100);
#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
qDebug("QNCM waiting random time: %d ms", iTimeToWait);
#endif
QTimer::singleShot(iTimeToWait, this, SLOT(delayedConfigurationUpdate()));
}
И вот в чем вопрос... В комментарии написано, что мы ждем от 2 до 6 секунд.
В функции мы берем минимум 1000 ms (одна секунда).
Мы берем по модулю 68 (не 60) и получаем 6.8 секунды.
Почему 68? Нахрена вообще понадобилась такая функция?
Столько вопросов... Но в этот раз не к языку. 🤡
GitHub
qt/src/plugins/bearer/symbian/symbianengine.cpp at 92fde5feca3d792dfd775348ca59127204ab4ac0 · openwebos/qt
Qt for webOS. Contribute to openwebos/qt development by creating an account on GitHub.
🤡5🤷♂1😭1
