Любителям C (если такие ещё остались)...

и задачки для интервью.
User avatar
Azazello
Уже с Приветом
Posts: 3179
Joined: 12 Jun 2001 09:01
Location: SPb,Russia->Rehovot, Israel->Cambridge, MA

Любителям C (если такие ещё остались)...

Post by Azazello »

Задача:

Дана функция:

[code:1:39a2c3fb24]
int f(int a, int b)
{
if (a > b) {
printf("a = %d, b = %d\n", a, b);
}
return a + b;
}
[/code:1:39a2c3fb24]

Заменить её макросом так, чтобы код, в котором эта функция вызывается в 3456 местах, продолжал компилироваться и правильно работать без единого изменения.

Задача из жизни (только функция предельно упрощена).
Всё чудесатее и чудесатее... (c) Alice
User avatar
Chapaev
Новичок
Posts: 96
Joined: 19 Jun 2001 09:01
Location: Canada

Re: Любителям C (если такие ещё остались)...

Post by Chapaev »

[quote:ad934e350b="Azazello"]Задача:

Дана функция:

[code:1:ad934e350b]
int f(int a, int b)
{
if (a > b) {
printf("a = %d, b = %d\n", a, b);
}
return a + b;
}
[/code:1:ad934e350b]

Заменить её макросом так, чтобы код, в котором эта функция вызывается в 3456 местах, продолжал компилироваться и правильно работать без единого изменения.

Задача из жизни (только функция предельно упрощена).[/quote:ad934e350b]

Остались еще :lol:

[code:1:ad934e350b]
#define F(a, b) (((a)>(b)? printf("a = %d, b = %d\n", (a), (b)): (a)), ((a) + (b)))
[/code:1:ad934e350b]
User avatar
Azazello
Уже с Приветом
Posts: 3179
Joined: 12 Jun 2001 09:01
Location: SPb,Russia->Rehovot, Israel->Cambridge, MA

Post by Azazello »

Приемлемо...
А теперь представьте, что строк не две, а больше. Т.е. решение с запятой по тем или иным причинам не работает...
Всё чудесатее и чудесатее... (c) Alice
User avatar
Chapaev
Новичок
Posts: 96
Joined: 19 Jun 2001 09:01
Location: Canada

Post by Chapaev »

[quote:ec0a1414c6="Azazello"]Приемлемо...
А теперь представьте, что строк не две, а больше. Т.е. решение с запятой по тем или иным причинам не работает...[/quote:ec0a1414c6]

Ну можно и так
[code:1:ec0a1414c6]
static char debug[128];
#define F(a, b) ((a) > (b)? printf("a = %d, b = %d\n", (a), (b)) \
- sprintf(debug, "a = %d, b = %d\n", (a), (b)) + ((a) + (b)): ((a) + (b)))
[/code:1:ec0a1414c6]

...и так
[code:1:ec0a1414c6]
#define F(a, b) ((a) > (b)? printf("a = %d, b = %d\n", (a), (b)) \
- fprintf(stderr, "a = %d, b = %d\n", (a), (b)) + ((a) + (b)): ((a) + (b)))
[/code:1:ec0a1414c6]
User avatar
Azazello
Уже с Приветом
Posts: 3179
Joined: 12 Jun 2001 09:01
Location: SPb,Russia->Rehovot, Israel->Cambridge, MA

Post by Azazello »

О!
10 баллов!

А теперь следующий вариант:

[code:1:2e3f670034]
extern int L;
extern uint M;

void f(int l, uint m, char a[], int b, char c[], char d[])
{
if ((l > L) && (m & M)) {
printf("%s: %d: %s(): %s\n", a, b, c, d);
fprintf(stderr, "%s: %d: %s(): %s\n", a, b, c, d);
}
}
[/code:1:2e3f670034]

И вот тут, к сожалению, ни запятую, ни арифметику применять нельзя - просто вот такое волюнтаристское ограничение...
Всё чудесатее и чудесатее... (c) Alice
tchicago
Уже с Приветом
Posts: 1009
Joined: 16 Sep 2001 09:01
Location: USA

Post by tchicago »

[quote:6d619715ee="Azazello"]Приемлемо...
А теперь представьте, что строк не две, а больше. Т.е. решение с запятой по тем или иным причинам не работает...[/quote:6d619715ee]

нет, неприемлемо. в следующем примере если бы F было
обычной функцией, печаталось бы "val=1".:

[code:1:6d619715ee]
#include <stdio.h>

#define F(a, b) (((a)>(b)? printf("a = %d, b = %d\n", (a), (b)): (a)), ((a) + (b)))

int val = 0;

int a( )
{
++val;
return 1;
}

int main( int argc, char** argv)
{
int b = F( a(), 0 );
printf( "val=%d\n", val );

return 0;
}

[/code:1:6d619715ee]

a что печататся ? :)
таким образом, приведенное решение не выполняет условие задачи
"[b:6d619715ee]и правильно работать без единого изменения[/b:6d619715ee]"
Last edited by tchicago on 08 Jun 2002 05:44, edited 1 time in total.
tchicago
Уже с Приветом
Posts: 1009
Joined: 16 Sep 2001 09:01
Location: USA

Post by tchicago »

[quote:61b15c7934="Azazello"]О!
10 баллов!

А теперь следующий вариант:

[code:1:61b15c7934]
extern int L;
extern uint M;

void f(int l, uint m, char a[], int b, char c[], char d[])
{
if ((l > L) && (m & M)) {
printf("%s: %d: %s(): %s\n", a, b, c, d);
fprintf(stderr, "%s: %d: %s(): %s\n", a, b, c, d);
}
}
[/code:1:61b15c7934]

И вот тут, к сожалению, ни запятую, ни арифметику применять нельзя - просто вот такое волюнтаристское ограничение...[/quote:61b15c7934]

здесь проще, поскольку не надо возвращать значения.
вроде ничего не мешает сделать (то же ограничение, что я упоминал выше):

[code:1:61b15c7934]
#define ff( l, m, a, b, c, d ) if (((l) > L) && ((m) & M)) { \
printf("%s: %d: %s(): %s\n", (a), (b), (c), (d)); \
fprintf(stderr, "%s: %d: %s(): %s\n", (a), (b), (c), (d)); \
}
[/code:1:61b15c7934]

такой вариант без того ограничения:

[code:1:61b15c7934]
#define ff( l, m, _a, _b, _c, _d ) if (((l) > L) && ((m) & M)) { \
char* a=(_a); int b=(_b); char* c=(_c); char* d=(_d); \
printf("%s: %d: %s(): %s\n", a, b, c, d); \
fprintf(stderr, "%s: %d: %s(): %s\n", a, b, c, d); \
}
[/code:1:61b15c7934]

но в таком варианте локальные переменные затеняют пространство
имен основной программы, поэтому возможна ошибка компиляции или
очень трудноуловимый глюк. Но можно применить вместо a,b,c,d такие имена,
которые точно не встретятся.
User avatar
Chapaev
Новичок
Posts: 96
Joined: 19 Jun 2001 09:01
Location: Canada

Post by Chapaev »

[quote:73c3f177c1="tchicago"][quote:73c3f177c1="Azazello"]О!
10 баллов!

А теперь следующий вариант:

[code:1:73c3f177c1]
extern int L;
extern uint M;

void f(int l, uint m, char a[], int b, char c[], char d[])
{
if ((l > L) && (m & M)) {
printf("%s: %d: %s(): %s\n", a, b, c, d);
fprintf(stderr, "%s: %d: %s(): %s\n", a, b, c, d);
}
}
[/code:1:73c3f177c1]

И вот тут, к сожалению, ни запятую, ни арифметику применять нельзя - просто вот такое волюнтаристское ограничение...[/quote:73c3f177c1]

здесь проще, поскольку не надо возвращать значения.
вроде ничего не мешает сделать (то же ограничение, что я упоминал выше):

[code:1:73c3f177c1]
#define ff( l, m, a, b, c, d ) if (((l) > L) && ((m) & M)) { \
printf("%s: %d: %s(): %s\n", (a), (b), (c), (d)); \
fprintf(stderr, "%s: %d: %s(): %s\n", (a), (b), (c), (d)); \
}
[/code:1:73c3f177c1]

такой вариант без того ограничения:

[code:1:73c3f177c1]
#define ff( l, m, _a, _b, _c, _d ) if (((l) > L) && ((m) & M)) { \
char* a=(_a); int b=(_b); char* c=(_c); char* d=(_d); \
printf("%s: %d: %s(): %s\n", a, b, c, d); \
fprintf(stderr, "%s: %d: %s(): %s\n", a, b, c, d); \
}
[/code:1:73c3f177c1]

но в таком варианте локальные переменные затеняют пространство
имен основной программы, поэтому возможна ошибка компиляции или
очень трудноуловимый глюк. Но можно применить вместо a,b,c,d такие имена,
которые точно не встретятся.[/quote:73c3f177c1]

С локальными переменными, конечно, лучше. Кроме того они убирают дефекты вышеприведенных примеров для ++ или -- аргумента.
Только с локальными переменными F(a--, ++b) будет работать как f(a--, ++b).
User avatar
Azazello
Уже с Приветом
Posts: 3179
Joined: 12 Jun 2001 09:01
Location: SPb,Russia->Rehovot, Israel->Cambridge, MA

Post by Azazello »

Контрпример для решения с фигурными скобками:
[code:1:7304be22a7]
if (condition)
f(currentLogLevel, LOG_TRACE,
__FILE__, __LINE__, __FUNCTION__, "condition holds");
else
f(currentLogLevel, LOG_TRACE,
__FILE__, __LINE__, __FUNCTION__, "condition doesn't hold");
[/code:1:7304be22a7]
Подсказка №2 - локальные переменные в реальной жизни не пригодились...
Всё чудесатее и чудесатее... (c) Alice
User avatar
Azazello
Уже с Приветом
Posts: 3179
Joined: 12 Jun 2001 09:01
Location: SPb,Russia->Rehovot, Israel->Cambridge, MA

Post by Azazello »

Глюк...
Всё чудесатее и чудесатее... (c) Alice
User avatar
Vlad G
Уже с Приветом
Posts: 596
Joined: 20 Jan 2002 10:01
Location: Israel

Re: Любителям C (если такие ещё остались)...

Post by Vlad G »

[quote:61051e8b82="Azazello"]Заменить её макросом [/quote:61051e8b82]
Можно полюбобытствовать, а чем функция мешала? Зачем заменять ее макросом, который и область кода и область данных увеличивает. Да еще и реализация ( и сопровождение) трудное?
Я думал, чт0 в жизни такими вещами не занимаются.
User avatar
Azazello
Уже с Приветом
Posts: 3179
Joined: 12 Jun 2001 09:01
Location: SPb,Russia->Rehovot, Israel->Cambridge, MA

Re: Любителям C (если такие ещё остались)...

Post by Azazello »

[quote:0b30a0cd7f="Vlad G"][quote:0b30a0cd7f="Azazello"]Заменить её макросом [/quote:0b30a0cd7f]
Можно полюбобытствовать, а чем функция мешала? Зачем заменять ее макросом, который и область кода и область данных увеличивает. Да еще и реализация ( и сопровождение) трудное?
Я думал, чт0 в жизни такими вещами не занимаются.[/quote:0b30a0cd7f]
Когда стек бесконечный - функциям нет равных... А когда стека всего 3-4K - тогда начинаются извращения...
Всё чудесатее и чудесатее... (c) Alice
User avatar
Azazello
Уже с Приветом
Posts: 3179
Joined: 12 Jun 2001 09:01
Location: SPb,Russia->Rehovot, Israel->Cambridge, MA

Post by Azazello »

Публикую решение.

[code:1:615510e938]
#define f(l,m,a,b,c,d) \
do { \
if (((l) > L) && ((m) & M)) { \
printf("%s: %d: %s(): %s\n", (a), (b), (c), (d)); \
fprintf(stderr, "%s: %d: %s(): %s\n", (a), (b), (c), (d)); \
} \
} while (0)
[/code:1:615510e938]
Last edited by Azazello on 13 Jun 2002 00:58, edited 1 time in total.
Всё чудесатее и чудесатее... (c) Alice
tchicago
Уже с Приветом
Posts: 1009
Joined: 16 Sep 2001 09:01
Location: USA

Post by tchicago »

[quote:80264ec71d="Azazello"]Публикую решение.

[code:1:80264ec71d]
#define f(l,m,a,b,c,d) \
do { \
if (((l) > L) && ((m) & M)) { \
printf("%s: %d: %s(): %s\n", (a), (b), (c), (d)); \
fprintf(stderr, "%s: %d: %s(): %s\n", (a), (b), (c), (d)); \
} while (0)
[/code:1:80264ec71d][/quote:80264ec71d]


oops...
а do .. while (0) зачем ?
чтоб загадочнее было ? :mrgreen:

кстати, одна } пропущена
User avatar
Azazello
Уже с Приветом
Posts: 3179
Joined: 12 Jun 2001 09:01
Location: SPb,Russia->Rehovot, Israel->Cambridge, MA

Post by Azazello »

Скобочка и вправду юыла пропущена, поправил.
А do {...} while(0) - чтобы приведённый мной контрпример (if (...) f(...); else ...) компилировался. Иначе никак...
Всё чудесатее и чудесатее... (c) Alice
Rostislav
Новичок
Posts: 82
Joined: 13 Jun 2002 04:30
Location: Dushanbe --> Tel Aviv

Post by Rostislav »

[quote:4c03254f0a="Azazello"]Скобочка и вправду юыла пропущена, поправил.
А do {...} while(0) - чтобы приведённый мной контрпример (if (...) f(...); else ...) компилировался. Иначе никак...[/quote:4c03254f0a]

Не понял. Как это не будет компилироваться?
Поподробнее можно?
tchicago
Уже с Приветом
Posts: 1009
Joined: 16 Sep 2001 09:01
Location: USA

Post by tchicago »

[quote:3a156db2ad="Rostislav"][quote:3a156db2ad="Azazello"]Скобочка и вправду юыла пропущена, поправил.
А do {...} while(0) - чтобы приведённый мной контрпример (if (...) f(...); else ...) компилировался. Иначе никак...[/quote:3a156db2ad]

Не понял. Как это не будет компилироваться?
Поподробнее можно?[/quote:3a156db2ad]

if( a ) { }; else { } - не компилится,
тогда как если f -- обычная функция,
if( a ) f(); else { } -- компилится
Rostislav
Новичок
Posts: 82
Joined: 13 Jun 2002 04:30
Location: Dushanbe --> Tel Aviv

Post by Rostislav »

Мне режет глаза точка с запятой после фигурной скобки, хотя не должно мешать. Я повидал столько чудес у разных компайлеров. Может в этом случае точка с запятой проблема для компайлера?
tchicago
Уже с Приветом
Posts: 1009
Joined: 16 Sep 2001 09:01
Location: USA

Post by tchicago »

[quote:b7edcc5f54="Rostislav"]Мне режет глаза точка с запятой после фигурной скобки, хотя не должно мешать. Я повидал столько чудес у разных компайлеров. Может в этом случае точка с запятой проблема для компайлера?[/quote:b7edcc5f54]

ну да, проблема именно в етой ;
с ней не компилится. Поверено на 2 компилерах
(c++.NET i tot, chto idet s tru64 unix).
User avatar
Azazello
Уже с Приветом
Posts: 3179
Joined: 12 Jun 2001 09:01
Location: SPb,Russia->Rehovot, Israel->Cambridge, MA

Post by Azazello »

Это не свойство компилятора, а синтаксис языка.
В операторе if () ... else ... после условия должен быть ровно один оператор или блок. Точка с запятой после блока - это пустой оператор, т.е. получается ДВА оператора (блок И пустой), а это запрещено синтаксисом.
Керниган-Ричи, 2-я редакция... (впрочем, и первая подойдёт в этом случае).
Всё чудесатее и чудесатее... (c) Alice
Rostislav
Новичок
Posts: 82
Joined: 13 Jun 2002 04:30
Location: Dushanbe --> Tel Aviv

Post by Rostislav »

[quote:46331ed8dd="Azazello"]Это не свойство компилятора, а синтаксис языка.
В операторе if () ... else ... после условия должен быть ровно один оператор или блок. Точка с запятой после блока - это пустой оператор, т.е. получается ДВА оператора (блок И пустой), а это запрещено синтаксисом.
Керниган-Ричи, 2-я редакция... (впрочем, и первая подойдёт в этом случае).[/quote:46331ed8dd]

Точно.
У меня это все уже рефлекторно.
Rostislav
Новичок
Posts: 82
Joined: 13 Jun 2002 04:30
Location: Dushanbe --> Tel Aviv

Post by Rostislav »

Прочитал книгу по real-time алгоритмам. Очень понравилась.
User avatar
Vlad G
Уже с Приветом
Posts: 596
Joined: 20 Jan 2002 10:01
Location: Israel

Post by Vlad G »

[quote:44a584d3a6="Rostislav"]Прочитал книгу по real-time алгоритмам. Очень понравилась.[/quote:44a584d3a6]
Читал с экрана или бумаги?
8K
Уже с Приветом
Posts: 5552
Joined: 20 Mar 2001 10:01
Location: SFBA

Post by 8K »

Решил не выпендриваться и всю критику поскипал.
Rostislav
Новичок
Posts: 82
Joined: 13 Jun 2002 04:30
Location: Dushanbe --> Tel Aviv

Post by Rostislav »

[quote:edaf6a116d="Vlad G"][quote:edaf6a116d="Rostislav"]Прочитал книгу по real-time алгоритмам. Очень понравилась.[/quote:edaf6a116d]
Читал с экрана или бумаги?[/quote:edaf6a116d]

С бумаги.
Начальник выкопал и купил на отдел. Книга в классическом понимании. Ha Амазоне есть:
http://www.amazon.com/exec/obidos/ASIN/ ... 82-3208923

Return to “Головоломки”