?

Log in

об одном строго типизированном языке (программистское) - Поклонник деепричастий [entries|archive|friends|userinfo]
Anatoly Vorobey

[ website | Website ]
[ userinfo | livejournal userinfo ]
[ archive | journal archive ]

Links
[Links:| English-language weblog ]

об одном строго типизированном языке (программистское) [июн. 26, 2010|08:10 pm]
Anatoly Vorobey
Будет интересно только программистам, знающим C++.

Небольшая загадка. Предугадайте, что напечатает следующая программа, не запуская ее. Потом проверьте себя, если интересно. Комменты не скрываются.
#include <iostream> #include <map> #include <string> using namespace std; int main() { map<int, string> m; double d = 123456.789; m[0] = d; cout << "m[0]=" << m[0]; return 0; }
СсылкаОтветить

Comments:
[User Picture]From: ice_hesitant
2010-06-26 05:15 pm
программисты которые не знают C++ хотят знать ответ.
(Ответить) (Thread)
[User Picture]From: senecarus
2010-06-26 06:25 pm
Они не программисты.
(Ответить) (Parent) (Thread) (Развернуть)
(Удалённый комментарий)
[User Picture]From: nmoroz
2010-06-26 05:18 pm
Только не говорите, что он найдет какой-то символ по такому числу.
(Ответить) (Thread)
[User Picture]From: spamsink
2010-06-26 05:27 pm
Чего ж не найти-то?
(Ответить) (Parent) (Thread)
[User Picture]From: blacklion
2010-06-26 05:36 pm
Какой символ оно найдёт мне не сообразить, но тут будет double-int-char цепочка.
gcc, гад, даже с -Wall молчит ка крыба об лёд.
(Ответить) (Thread)
From: 9000
2010-06-26 05:41 pm
Если 12, то это form feed, экран должна очистить.

(Ответить) (Parent) (Thread) (Развернуть)
[User Picture]From: msh
2010-06-26 05:40 pm
поскольку operator= бывает для string&, char* и char, d превратится в char с предупреждением от компилятора. Какой конкретно char - не знаю, но явно ничего хорошего
(Ответить) (Thread)
[User Picture]From: blacklion
2010-06-26 05:42 pm
Ну вот g++ не даёт никаких предупреждений. MS/Intel под рукой нет, через 10 минут попробую в clang, который славится своей ворчливостью и правильностью этой ворчливости, если он вообще такой C++ съест (не факт).
(Ответить) (Parent) (Thread) (Развернуть)
From: renatm
2010-06-26 06:25 pm
Сначала вообще никаких идей не было, и не был уверен, что это вообще компилируется. Решил откомпилировать, но видимо зря, потому что MSVC выдал предупреждение

warning C4244: 'argument' : conversion from 'double' to 'char', possible loss of data

по которому сразу стало ясно, что дабл будет конвертиться в char.

Вообще, я считаю, что в нормальном языке программирования такое не должно компилироваться :)
(Ответить) (Thread)
[User Picture]From: blacklion
2010-06-26 06:36 pm
Вообще, я считаю, что в нормальном языке программирования такое не должно компилироваться :)
Ну да, “система типов” C/C++ ужасна, это любой хаскеллист скажет :)))
(Ответить) (Parent) (Thread) (Развернуть)
[User Picture]From: itman
2010-06-26 06:36 pm
Вообще, за неявные преобразования в Сях авторов языка нужно очень и очень ругать. Другое дело, что язык этот создавался в дремучие времена, когда не очень верили в то, что строгая типизация нужна. Да даже и сейчас я вижу много людей, которые бьют себя пяткой в грудь и кричат, что они крутые, поэтому вполне могут писать на скриптовых языках, где преобразуется вообще все во все. В Си++ хоть ограничения есть.
(Ответить) (Thread)
[User Picture]From: psilogic
2010-06-26 08:11 pm
Ну в MSVS система warning-ов вполне кошерно такие вещи отлавливает. Главное болт беречь, на варнинги его не класть.
(Ответить) (Parent) (Thread) (Развернуть)
[User Picture]From: greps
2010-06-26 06:42 pm

:)

Ну да, ну да, а потом мы долго и нудно пишем языке программмирования модуль для конвертирования -
Convert.Int2Float, Convert.Ptr2Str and so on and so on...
(Ответить) (Thread)
From: 9000
2010-06-26 08:49 pm

Re: :)

Конверсия без потери информации — ok, хотя можно и warning выдать. И вообще, между числами — одно дело, между числом и строкой — совсем другое, imho.
(Ответить) (Parent) (Thread)
[User Picture]From: rogovsky
2010-06-26 06:48 pm
Нормальный компилятор за такое должен руки поотрывать!
(Ответить) (Thread)
[User Picture]From: egle
2010-06-26 07:52 pm
+1
Tолько не отрывает, и вообще только ворнинг выдает... Я, на самом деле, не могу понять, почему он превращает эту фигню в char.
(Ответить) (Parent) (Thread) (Развернуть)
[User Picture]From: _navi_
2010-06-26 08:18 pm
Самое интересное во всей этой истории — это отутствие какой-либо вменяемой системы с предупреждениями о неявных преобразованиях в разных версиях gcc/g++: кажется, было даже так, что g++ какой-то версии на Mac OS X не выдавал предупреждение, а на Linux выдавал.
(Ответить) (Thread)
[User Picture]From: helvegr
2010-06-27 08:13 am
-Wconversion, -Wsign-conversion
(Ответить) (Parent) (Thread) (Развернуть)
[User Picture]From: meshko
2010-06-26 08:18 pm
Ну тут С++ не виноват -- если есть предупреждение. У меня есть ,)
(Ответить) (Thread)
From: lazyreader
2010-06-26 08:43 pm
Да нет, именно C++ виноват, а вот именно компилятор (если есть предупреждение) - молодец.
(Ответить) (Parent) (Thread) (Развернуть)
From: lazyreader
2010-06-26 08:45 pm
Вообще, неявное преобразование типов - это одна из двух или трёх самых серьёзных проблем C++.
(Ответить) (Thread)
(Удалённый комментарий)
[User Picture]From: dimrub
2010-06-26 08:53 pm
Не глядя. Удивлен, что это компилируется. Я бы предположил, что напечатает то, что в данной архитектуре произойдет, если из представление double взять нижний байт, и записанное там число использовать в качестве аски-кода символа (т.е. этот символ и напечатает).
(Ответить) (Thread)
[User Picture]From: avva
2010-06-26 10:29 pm
Примерно так, да. Меня тоже удивило, что компилируется, а уж то, что предупреждений не выдает... (но оказывается, это по-разному даже в разных версиях gcc, как в комментах обсуждают).
(Ответить) (Parent) (Thread)
From: (Anonymous)
2010-06-26 10:22 pm
хорошая бага, я почти такую же недавно в продакшен коде нашел.
(Ответить) (Thread)
[User Picture]From: peretyatkov
2010-06-27 06:32 am

...

Типа данных string в С++ - нет.
Это класс расширения стандарта языка из STL.
И здесь очень часто многое прокатывает.
Хоть чего делай.
...
А потому то что напечатало - не удивился.
Впрочем даже и в отладчике не исследовал.
Вот это напечатало: m[0]=@.
(Ответить) (Thread)
[User Picture]From: spacediver
2010-06-27 08:05 am
Напечатал m[0]=@.

И почему я ожидал, что в m[0] окажется какое-нибудь строковое представление вещественного числа?.. %) Давно не программировал на сем, использовал здравый смысл.
(Ответить) (Thread)
[User Picture]From: wildernesscat
2010-06-27 11:57 am
Ничего не выдаёт ...
> ./stam.out | od -bc
0000000 155 133 060 135 075 000
          m   [   0   ]   =  \0
0000006
>
(Ответить) (Thread)
[User Picture]From: zigmar
2010-06-27 12:26 pm
Я сказал бы, что такое не откомпилируется, так как не не определен оператор присвоения для ссылки на стриг и double. Но так как явно вопрос с подвохом и код скомпилируется, то я придумал такую безумную теорию:
Какой-то из конструкторов string-а который принимает size_t или int (кажется, он инициализует пустой стринг такой длинны или резервирует данное кол-во места) почему-то не объявлен как explicit, и с помощью двойного неявного преобразования (разве такое бывает?!) double->int/size_t->string создаст пустой или длинный стринг из пробелов(?), который и поместит в map.
(Ответить) (Thread)
[User Picture]From: zigmar
2010-06-27 12:30 pm
Хмм, посмотрел документацию, вроде нету такого конструктора, чтоб один int аргумент получал.
http://www.cplusplus.com/reference/string/string/string/
http://www.sgi.com/tech/stl/basic_string.html

Пойду компилировать и смотреть. Блин, а я то думал, что неплохо в тонкостях с++ разбираюсь :)
(Ответить) (Parent) (Thread)
[User Picture]From: zigmar
2010-06-27 02:36 pm
Кстати, еще из забавных (правда безобидных) особенностей С:

int a[10];
a[4] = 1; /* ok */
4[a] = 1; /* also ok, does the same */

/* Hint: compiler interprets a[b] as *(a+b) */
(Ответить) (Thread)
[User Picture]From: dikij
2010-06-29 09:21 am
Страуструп в "The C++ Programming Language" по этому поводу пишет:
The fundamental types can be converted into each other in a bewildering number of ways. In my opinion, too many conversions are allowed.

И об'ясняет, как такой conversion (double→char) работает:
...conversion from a floating-point type to an integer type truncates. ... The behavior is undefined if the truncated value cannot be represented in the destination type. ... Conversions from integer to floating types are as mathematically correct as the hardware allows. Loss of precision occurs if an integral value cannot be represented exactly as a value of the floating type.
(Ответить) (Thread)
[User Picture]From: dikij
2010-06-29 09:22 am
Ничего хорошего в таком превращении, конечно, нет.
(Ответить) (Parent) (Thread)
[User Picture]From: zyama_krendel
2010-07-01 03:03 pm
Маленький вопрос: если дело только в conversion, зачем там вся эта история с map? Просто написать что-нибудь такого типа:

string s = 123456.789;
cout << "s=" << s << endl;


будет недостаточно?
(Ответить) (Thread)
[User Picture]From: eoai
2010-07-06 07:29 am
Ну, похоже, тут проблема идет слева направо, а не наоборот, как кажется.

m[0] = d; - при исполнении выглядит как

string& x = m.operator[](0); // что само по себе очень странно
x.ctor((char)d); // пустой блок памяти вернулся, вызывается ктор

ну, а 123456.789 транформируется в 123456 = 0x0001e240, последний байт = 40 = '@'

Очередной отличный выстрел в ногу.

(Ответить) (Thread)
[User Picture]From: eoai
2010-07-06 07:31 am
Обманул, не ctor. operator=(char)
(Ответить) (Parent) (Thread) (Развернуть)