Программистские задачки и хитрости

Аватара пользователя
Serg
Мастер
Сообщения: 21844
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5133
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Serg »

Ладно, это было легко гугить. :)

Вот ещё:

Код: Выделить всё

$ cat t.c
#include <stdio.h>

void print(int a, int b) {
	printf("print: a=%d, b=%d\n", a), b;
}

void main(void) {
	int x = 5, y = 8;

	print(x, y);
}
$ make t
cc     t.c   -o t
$ ./t
print: a=5, b=8
$ 
Где ошибка и почему работает? :)
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Duhas
Мастер
Сообщения: 1772
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 268
Настоящее имя: Андрей
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Duhas »

ну ошибка то вроде очевидна, или очевидны, или нет их и так задумано )
а работает из-за единицы )
я подозреваю не любой компилятор это прожует?
дичь какаято :idiot:
Аватара пользователя
Serg
Мастер
Сообщения: 21844
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5133
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Serg »

Какая такая единица?..

Самый строгий gcc проглатывает. :)
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Аватара пользователя
selenur
Почётный участник
Почётный участник
Сообщения: 4358
Зарегистрирован: 21 авг 2013, 19:44
Репутация: 1526
Настоящее имя: Сергей
Откуда: Новый Уренгой
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение selenur »

UAVpilot писал(а):Самый строгий gcc проглатывает.
printf('print: a=%d, b=%d\n', a), b; <-- странно как 'b' находясь снаружи не вызывает ошибку :thinking:
Мой сайт: http://selenur.ru
Исходники моих программ: https://github.com/selenur
Аватара пользователя
Serg
Мастер
Сообщения: 21844
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5133
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Serg »

Собственно с точки зрения компилятора никакой ошибки и нет. Пусть это будет ещё одной задачкой - объяснить почему. :)
Основная задача - объяснить почему выдаётся ожидаемый результат. :)
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Аватара пользователя
Serg
Мастер
Сообщения: 21844
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5133
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Serg »

UAVpilot писал(а):Какая такая единица?..
Понял какая единица - это опечатка, я пробовал несколько вариантов, но оставил один, поправил.
Другой вариант покажу как подсказку, если с ответами совсем грустно будет... :)
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Аватара пользователя
Сергей Саныч
Мастер
Сообщения: 9028
Зарегистрирован: 30 май 2012, 14:20
Репутация: 2815
Откуда: Тюмень
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Сергей Саныч »

я готов допустить, что ответ кроется в случайном совпадении ячейки в стеке, через которую передается второй параметр в printf() и динамически определяемой переменной b.
Однако ж у меня выдает некое абстрактное значение. Да и ругается при компиляции, мол, аргУментов не хватает.

Код: Выделить всё

cnc@cnc-desktop:~/Рабочий стол/test$ cat t.c
#include <stdio.h>

void print(int a, int b) {
  printf("print: a=%d, b=%d\n", a), b;
}

void main(void) {
   int x = 5, y = 8;

   print(x, y);
}

cnc@cnc-desktop:~/Рабочий стол/test$ make t
cc     t.c   -o t
t.c: In function ‘print’:
t.c:4: warning: too few arguments for format
cnc@cnc-desktop:~/Рабочий стол/test$ ./t
print: a=5, b=-1077941240
cnc@cnc-desktop:~/Рабочий стол/test$ 

Что до запятой, то это допустимый разделитель выражений.
Чудес не бывает. Бывают фокусы.
Аватара пользователя
Serg
Мастер
Сообщения: 21844
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5133
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Serg »

Сергей Саныч писал(а):я готов допустить, что ответ кроется в случайном совпадении ячейки в стеке, через которую передается второй параметр в printf() и динамически определяемой переменной b.
Всё правильно, только совпадение совсем не случайное, а предопределённое. :)
Вот так кстати тоже будет работать:

Код: Выделить всё

printf("print: a=%d, b=%d\n", a);
Сергей Саныч писал(а):Что до запятой, то это допустимый разделитель выражений.
И это правильно.
Сергей Саныч писал(а):Однако ж у меня выдает некое абстрактное значение. Да и ругается при компиляции, мол, аргУментов не хватает.
Что за компилятор? У меня так:

Код: Выделить всё

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/9/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-redhat-linux
Configured with: ../configure --enable-bootstrap --enable-languages=c,c++,fortran,objc,obj-c++,ada,go,d,lto --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-gcc-major-version-only --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --with-isl --enable-offload-targets=nvptx-none --without-cuda-driver --enable-gnu-indirect-function --enable-cet --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
Thread model: posix
gcc version 9.2.1 20190827 (Red Hat 9.2.1-1) (GCC)

Код: Выделить всё

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/6/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 6.3.0-18+deb9u1' --with-bugurl=file:///usr/share/doc/gcc-6/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-6 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-6-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-6-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-6-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 6.3.0 20170516 (Debian 6.3.0-18+deb9u1) 
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Аватара пользователя
Serg
Мастер
Сообщения: 21844
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5133
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Serg »

Эта задачка была придумана для иллюстрации того факта, что язык С - это не язык высокого уровня, а скорее макроассемблер высокого уровня, т.е. что напишешь на нём, ровно то и получишь, что программисту нужно самому заботится о соответствии типов, правильности адресации и т.п.
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Аватара пользователя
MX_Master
Мастер
Сообщения: 6661
Зарегистрирован: 27 июн 2015, 19:45
Репутация: 2807
Настоящее имя: Миша
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение MX_Master »

IC
в нём нет ничего лишнего
Duhas
Мастер
Сообщения: 1772
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 268
Настоящее имя: Андрей
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Duhas »

UAVpilot писал(а): Всё правильно, только совпадение совсем не случайное, а предопределённое. :)
ок, 1 - опечатка.

в целом то понятно что второй аргумент передается "паразитным" способом.. а вот с подробностями не дружу, не подскажете где хорошо описана передача аргументов в функцию? в случае компиляции под те же AVR это может быть и стек и регисты на сколь я понимаю?
Аватара пользователя
Serg
Мастер
Сообщения: 21844
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5133
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Serg »

В самом описании С (не синтаксиса, а "внутренностей") и его компилятора, про размещение переменных, констант, параметров функций, кода.
Касательно конкретной платформы имеет смысл почитать про режимы оптимизаци компилятора и про линкер про организацию памяти. Регистры для размещения переменных редко используются.
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Duhas
Мастер
Сообщения: 1772
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 268
Настоящее имя: Андрей
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Duhas »

название какое нибудь есть на уме? типа K&R
Аватара пользователя
Сергей Саныч
Мастер
Сообщения: 9028
Зарегистрирован: 30 май 2012, 14:20
Репутация: 2815
Откуда: Тюмень
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Сергей Саныч »

UAVpilot писал(а):Что за компилятор?
Достаточно древний

Код: Выделить всё

cnc@cnc-desktop:~/Рабочий стол/test$ gcc -v
Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.4.3-4ubuntu5.1' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --program-suffix=-4.4 --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-plugin --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i486 --with-tune=generic --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu
Thread model: posix
gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5.1) 
cnc@cnc-desktop:~/Рабочий стол/test$
Чудес не бывает. Бывают фокусы.
Аватара пользователя
Serg
Мастер
Сообщения: 21844
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5133
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Serg »

Duhas писал(а):название какое нибудь есть на уме? типа K&R
Сейчас сложно сказать - я уже давно книжки по С не читал... :)
Попробовал гуглить "C размещение переменных" - предлагает и подходящие ссылки...
Сергей Саныч писал(а):Достаточно древний
gcc v 4.* - это страшный компилятор, в нем "засад" столько, что даже непонятно как программы собранные им работают. :) Что-то более-менее вменяемое начинается с v4.8.
А программка эта даже с опцией -pedantic компилится.
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Аватара пользователя
MX_Master
Мастер
Сообщения: 6661
Зарегистрирован: 27 июн 2015, 19:45
Репутация: 2807
Настоящее имя: Миша
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение MX_Master »

Есть у меня одна задачка, с лёту не придумал решения, поэтому применил костыль. Может, кто подскажет.

ДАНО:
В проекте OrangePi+LinuxCNC в сопроцессоре есть системный таймер. Работает на той же частоте, что и сопроцессор (450мгц). Счётчик у таймера 32-битный. Т.к. таймер работает постоянно, значение счётчика довольно часто переполняется (uint32) и отсчёт начинается заново, с нуля.

ЗАДАЧА:
Сделать точную "busy waiting" паузу на указанное кол-во тактов с помощью системного таймера, учитывая, что его счётчик часто переполняется
Аватара пользователя
Argon-11
Мастер
Сообщения: 1870
Зарегистрирован: 07 июн 2017, 17:48
Репутация: 438
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Argon-11 »

Ну я б сказал, переполнение раз в 9 секунд - это нечасто :)
Зная заведомо, что состояние busy меньше периода переполнения таймера, то алгоритм простой. Берем начальное значение и в цикле сравниваем текущее с начальным.
Текущее больше начального -> вычисляем разницу (текущее - начальное).
наоборот -> (период таймера - начальное + текущее).
Если это и есть костыль, то на самом деле это не костыль, а, наверное, единственно правильное решение.
Аватара пользователя
Serg
Мастер
Сообщения: 21844
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5133
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Serg »

В данном случае есть более простое решение - просто забить на переполнение. :)
Да, счётчик таймера переполняется, но это никак не сказывается на результате. :)
Поясню:
счётчик таймера - 32-битное целое, максимальное значение - 4294967295.
Истечение таймаута проверяется так:
if((HAL_GetTick()-tickstart) >= Timeout) ...
Видите тут обработку переполнения? И я не вижу, а она есть! :)
Допустим tickstart = 4294967285 (значение таймера в момент начала отсчёта задержки). Пусть задержка должна быть 100 тиков.
Через 10 тиков HAL_GetTick() вернёт 0, соотв. HAL_GetTick() - tickstart = 0 - 4294967285 = 10, ибо обе переменные бесзнаковые целые. Далее HAL_GetTick() вернёт 1 - результатом вычитания будет 11. Ну и так далее...

На этом кстати часто попадаются всякие форумные хаятели HAL и Cube - приводят в качестве примера косячного кода "переполнение" системного таймера... :)

P.S. У нас где-то была тема про программирование stm32, но наверно это пусть будет в этой.
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Аватара пользователя
MX_Master
Мастер
Сообщения: 6661
Зарегистрирован: 27 июн 2015, 19:45
Репутация: 2807
Настоящее имя: Миша
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение MX_Master »

Да

Код: Выделить всё

if ((tick - tickstart) < timeout) ;
это довольно быстро. Просто, я думал, а вдруг в природе есть что-то ещё быстрее. Типа

Код: Выделить всё

if (tick < tickend) ;
и чтоб была возможность делать точную паузу больше, чем на 9 секунд (:
Аватара пользователя
Сергей Саныч
Мастер
Сообщения: 9028
Зарегистрирован: 30 май 2012, 14:20
Репутация: 2815
Откуда: Тюмень
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Сергей Саныч »

MX_Master писал(а):чтоб была возможность делать точную паузу больше, чем на 9 секунд
Если невозможно использовать прерывание по переполнению счетчика, можно попробовать так:

Код: Выделить всё

uint64_t longtick; // Долгий таймер
uint32_t curtick, prevtick = 0; // Вспомогательные переменные, причем prevtick должна быть глобальной или статической 
............
// Этот фрагмент вызываем как угодно часто, но не реже одного раза за 2^32 тактов
  curtick = tick; // Читаем и запоминаем счетчик
  longtick += curtick - prevtick; // Разность текущего и предыдущего отсчетов прибавим к 64-битному счетчику
  prevtick = curtick; // Заменим предыдущее значение на текущее
Последний раз редактировалось Сергей Саныч 23 ноя 2019, 18:54, всего редактировалось 1 раз.
Чудес не бывает. Бывают фокусы.
Ответить

Вернуться в «Оффтоп»