Сеанс чёрной магии
Aug. 11th, 2016 03:59 pmКак поменять порядок аргументов, передаваемых в функцию, особо извращённым способом. И почему это работает.
#include <math.h>
#include <stdio.h>
double DoubleToTheInt(double base, int power) {
return pow(base, power);
}
int main() {
// cast to a function pointer with arguments reversed
double (*IntPowerOfDouble)(int, double) =
(double (*)(int, double))&DoubleToTheInt;
printf("(0.99)^100: %lf \n", DoubleToTheInt(0.99, 100));
printf("(0.99)^100: %lf \n", IntPowerOfDouble(100, 0.99));
}
The code above never actually defines the function IntPowerOfDouble — because there is no function IntPowerOfDouble. It's a variable that points to DoubleToTheInt, but with a type that says it likes its integer arguments to come before its doubles.
You might expect the IntPowerOfDouble to take its arguments in the same order as DoubleToTheInt, but cast the arguments to a different type, or something like that. But that's not what happens.
Try it out — you'll see the same result value printed on both lines.
emiller@gibbon ~> clang something.c
emiller@gibbon ~> ./a.out
(0.99)^100: 0.366032
(0.99)^100: 0.366032
Программиста, который такие трюки применяет, надорасстреливать увольнять.
#include <math.h>
#include <stdio.h>
double DoubleToTheInt(double base, int power) {
return pow(base, power);
}
int main() {
// cast to a function pointer with arguments reversed
double (*IntPowerOfDouble)(int, double) =
(double (*)(int, double))&DoubleToTheInt;
printf("(0.99)^100: %lf \n", DoubleToTheInt(0.99, 100));
printf("(0.99)^100: %lf \n", IntPowerOfDouble(100, 0.99));
}
The code above never actually defines the function IntPowerOfDouble — because there is no function IntPowerOfDouble. It's a variable that points to DoubleToTheInt, but with a type that says it likes its integer arguments to come before its doubles.
You might expect the IntPowerOfDouble to take its arguments in the same order as DoubleToTheInt, but cast the arguments to a different type, or something like that. But that's not what happens.
Try it out — you'll see the same result value printed on both lines.
emiller@gibbon ~> clang something.c
emiller@gibbon ~> ./a.out
(0.99)^100: 0.366032
(0.99)^100: 0.366032
Программиста, который такие трюки применяет, надо
no subject
Date: 2016-08-11 01:17 pm (UTC)Я тут в catdoc на гораздо более простые случаи напарвывался, что они оказывались несовместимыми с clang, например.
Причем когда я году в 95 это писал, оно совершенно не казалось черной магией - в DOS все так делали.
(а как я в турбпопаскалевских real mode указателях прятал целый байт дополнительной информации... Мог бы и 12 бит, но решил не жадничать).
no subject
Date: 2016-08-11 01:18 pm (UTC)no subject
Date: 2016-08-11 01:26 pm (UTC)no subject
Date: 2016-08-11 01:28 pm (UTC)no subject
Date: 2016-08-11 01:37 pm (UTC)воринга не кинет, что "ты, хозяин, в своем праве так делать - но то что ты делаешь небезопасно"?
no subject
Date: 2016-08-11 01:40 pm (UTC)(и неочевидной читаемости традиционного для него кода тоже - со всеми этими указателями на места, где лежат указатели на места, где лежат фактические параметры и т.п. - ну или хотя бы той картинки программистского юмора про = вместо ==, которую сегодня все репостят в фэйсбуке).
no subject
Date: 2016-08-11 01:44 pm (UTC)Подобная фигня возможна только в низкоуровневых языках, но в более высокоуровневых свои погремушки.
no subject
Date: 2016-08-11 01:49 pm (UTC)no subject
Date: 2016-08-11 01:55 pm (UTC)Более глубоких наворотов в стандартном паскале вроде бы не ыбо?
Или проблема как раз в том, что в Си можно много чего нетривиального соорудить, средвста языка позволяют а не дают по рукам?
no subject
Date: 2016-08-11 02:09 pm (UTC)Я имел в виду ситуацию, когда зачем-то передают не ссылку на место хранения данных, а ссылку на ссылку. Сходу, правда, не вспомнил, где именно мне такое попадалось.
>Или проблема как раз в том, что в Си можно много чего нетривиального соорудить, средвста языка позволяют а не дают по рукам?
Да, мне кажется, что это проблема. Вероятность того, что кто-то сделает слабочитаемым код с помощью какого-нибудь выпендрежа, без которого можно было обойтись, гораздо больше, чем того, что без подобных фокусов будет ну прямо не жить.
no subject
Date: 2016-08-11 02:18 pm (UTC)Регулярно приходится и сталкиваться, и самому применять. Ситуация вложенных структур данных и вообще луковичной логики. Например, в оптимизатор передается структура, задающая параметры его работы включая какую, собственно, функцию оптимизировать. Соответственно, аргументом этой функции будет указатель на еще одну структуру данных (в простейшем случае - массив).
Или вариант когда надо получить отсортированный по какому-то критерию список объектов, которые нельзя физически реаллокировать (скажем, слишком большие), и каждый содержит какие-то массивы.
В обоих случаях перехлж на плюсы и объекты проблему маскирует, но не решает.
> Да, мне кажется, что это проблема. Вероятность того, что кто-то сделает слабочитаемым код с помощью какого-нибудь выпендрежа, без которого можно было обойтись, гораздо больше, чем того, что без подобных фокусов будет ну прямо не жить.
Я думаю, что для большинства применений утверждение если и не 100% справедливо, то близко к этому:) Но есть отдельные направления, где без таких возможностей тяжело, и где программисты обычно обладают квалификацией и самодисциплиной:)
Может быть скажу ересь, но в отличии от ситуации 20-ти летней давности и С, и С++ - нишевые языки, в большинстве случаев вместо них стоит использовать языки более высокого уровня.
no subject
Date: 2016-08-11 03:09 pm (UTC)no subject
Date: 2016-08-11 09:22 pm (UTC)Да, вполне возможно.
Просто мне в свое время пришлось разбираться со здоровым куском кода (несколько сотен строк, в каждую из которых было напихано,в лучшем случае, всего лишь несколько операторов - а не десятка полтора, скажем), написанных таким вот любителем, э, программистских лайфхаков (это был не си, а mumps, если что) - мне надо было в него функционал добавить. Степень моего счастья от этой задачи, скажем так, было сложно недооценить :) Поэтому я числю себя большим фанатом понятного кода :)
no subject
Date: 2016-08-11 09:38 pm (UTC)no subject
Date: 2016-08-11 02:32 pm (UTC)Ссылку на ссылку передают сплошь и рядом, когда нужно вернуть ссылку из функции, а непосредственно возвращаемое значение почему-либо уже занято.
no subject
Date: 2016-08-11 01:51 pm (UTC)no subject
Date: 2016-08-11 01:58 pm (UTC)no subject
Date: 2016-08-11 02:25 pm (UTC)Ну не знаю, я посмотрел на код, сказал «а, ну да, calling convention: целые ходят через один набор регистров, плавающая точка через другой». Потом пошёл по ссылке и получил подтверждение гипотезы.
Знания о ABI, если не изучать целенаправленно, появляются из сеансов отладки/декомпиляции чего-нибудь в условиях, когда исходник и/или отладочная информация недоступны.
no subject
Date: 2016-08-11 01:52 pm (UTC)no subject
Date: 2016-08-11 02:02 pm (UTC)no subject
Date: 2016-08-11 02:12 pm (UTC)no subject
Date: 2016-08-11 02:21 pm (UTC)Или что, пример реально выловлен из какого-то рабочего проекта?!
no subject
Date: 2016-08-11 02:25 pm (UTC)Провел проверку:)
Date: 2016-08-11 02:39 pm (UTC)под юниксом gcc купился:(
no subject
Date: 2016-08-11 04:50 pm (UTC)no subject
Date: 2016-08-11 06:23 pm (UTC)