Тонкости C/C++

Тема в разделе "LANGS.C", создана пользователем Nafanya, 5 фев 2011.

  1. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    green
    Я отвечал на вопрос Nafanya-и, почему f() является функцией с переменным числом параметров. Ответ, в Си любая _cdecl функция это функция с переменным числом параметров.
     
  2. Nafanya

    Nafanya Member

    Публикаций:
    0
    Регистрация:
    26 июл 2006
    Сообщения:
    581
    Для WinXP sp3 фурычит. Функция с переменным числом параметров, без именного аргумента, считает сумму пяти переданных аргументов. Вроде получилось без асм-вставок.
    Код (Text):
    1. #include <intrin.h>
    2. #include <stdio.h>
    3. int func()
    4. {
    5. int i;
    6. int arg,sum=0;
    7. int* Address =(int*) _AddressOfReturnAddress();
    8. Address++;
    9.  
    10. for(i=0;i<5;i++)
    11.     {
    12.          arg= *Address;
    13.          Address++;
    14.          sum=arg+sum;
    15.     }
    16.  return(sum);
    17. }
    18.  
    19. int main(void)
    20. {
    21. printf("%d",func(1,2,3,4,5));
    22. getchar();
    23. return 0;
    24. }
    Согласен.
    Точно. Вот где истина то крылась.
     
  3. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.330
    вариант, что тебе предлагал GoldFinch надежнее, тк ты кучу всего не учитываешь, что в принципе учитывают ва_листы:
    Код (Text):
    1. va_start(va, *_AddressOfReturnAddress());
    то, что предлагает GRRRLPower предназначен для людей, которые не удивляются, что это работает, а знают почему это работает...
     
  4. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    Да ладн, ребят, зачем так вот пряма эта периносимость нужна. Подумаешь пару асм-вставок ничево, в этом таково страшново нет.
     
  5. krabz

    krabz New Member

    Публикаций:
    0
    Регистрация:
    26 май 2010
    Сообщения:
    135
    Чисто так к сведению: попробовал добавить в сорц
    Код (Text):
    1. int myfunc (...);
    cl не схавал.
    с хотя бы одним именованным параметром хавает.
     
  6. Nafanya

    Nafanya Member

    Публикаций:
    0
    Регистрация:
    26 июл 2006
    Сообщения:
    581
    Rel
    Ну что там не знать... он объявляет указатель на двойное слово ( int* stack;) затем пихает в него базу стекового кадра, затем относительно базы берет смещение +2 и +3 DWORD'а в сторону старших адресов по стеку (return *(stack + 2) + *(stack + 3);) так как это и будут адреса аргументов,затем берет значения аргументов по адресам(разыменовывает указатели), затем возвращает сумму аргументов . Смещение +1 DWORD - адрес возврата из функции.

    Вариант GoldFinch'а более туманен, т.к. нет законченной реализации...
     
  7. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.330
    ну смотри... как минимум первый вопрос: как определить количество переданных параметров... вопрос с подвохом, ответ - никак... ну кроме каких-нить нетривиальных хаков... функция должна как-то понять, какие параметры были в нее переданы... поэтому в ней (как например в функции printf) должен быть как минимум один явный параметр, указывающий, какие параметры были переданы в функцию... поэтому с точки зрения компилятора и нормального программиста функция func(...) бессмысленна... далее, следующий вопрос: как быть с параметрами, размер которых не равен 4 байтам? предлагаю тебе написать аналогичный код для функции, которая будет принимать два параметра типа char, и для функции, которая будет принимать два параметра типа double и посмотреть результат... эти вопросы, как и проблема кроссплатформенности (по разрядности (x86/x64)), и проблема кросскомпиляции (хотя бы msvc/gcc-семейство) решены в реализации ва_листов... и кстати, я считаю вариант с ва_листами вполне переносимым, необходимо только написать переносимую функцию получения указателя на параметры на стеке... хотя еще раз: func(...) - лишена смысла...
     
  8. newbie

    newbie New Member

    Публикаций:
    0
    Регистрация:
    2 дек 2008
    Сообщения:
    1.246
    Денег не хватит у тебя ;)
     
  9. GRRRLPower

    GRRRLPower New Member

    Публикаций:
    0
    Регистрация:
    17 авг 2010
    Сообщения:
    46
    Мой способ оказался более-менее переносимым, на виндовсе и на линуксе работает же, компилируется в gcc и msvc :)
    http://codepad.org/QAQhi93m

    Только вот кому нужны эти функции без формальных параметров вообще...
     
  10. Nafanya

    Nafanya Member

    Публикаций:
    0
    Регистрация:
    26 июл 2006
    Сообщения:
    581
    GRRRLPower
    Такие вопросы с подколом задают на собеседованиях(больше это нигде не нужно). Напишут бред и спросят типа компилятор выдаст ошибку или нет. Смотришь - вроде бред, говоришь выдаст ошибку. А они как подпрыгнут от радости - "А вот и нет, пропустит!":)
    Вот вы сможете ответить - сколько байт памяти занимает объект пустого класса? И почему?
     
  11. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    GRRRLPower
    Какая ж это переносимость, если у вас в фактически отдельный вариант кода для каждого компилятора?
    Кроме того, как насчёт корректной работы с ключом оптимизации -fomit-frame-pointer ? А как насчёт других аппаратных платформ? x64, скажем?

    Эти ф-ции нужны. В С это позволяет сделать развязку прототипа ф-ции и её реализации в случае, если интерфейс ф-ции неопределён на этапе компиляции.
    В С++ определения func(...) выступают как default case различных перегрузок func - позволяют обработать вызов ф-ции с непредусмотренным набором параметров. Широко используется в метапрограммировании.
     
  12. GRRRLPower

    GRRRLPower New Member

    Публикаций:
    0
    Регистрация:
    17 авг 2010
    Сообщения:
    46
    На собеседованиях такие вопросы задают только идиоты, а на нормальных собеседованиях даются практические задачи, чтобы программист мог порассуждать, порешать ее на глазах у того, кто принимает собеседование. Вплоть до того, что программисту будет дан доступ в интернет. Вот зачем мне знать на практике, что объект пустого класса занимает 1 байт, и что связано это с адресацией? Вы уже доказали, что можно быть хорошим теоретиком, но быдлокодером :)
    Я могу задать Вам более практические вопросы по C++, на которые Вы не факт, что ответите.

    Да хреновая это переносимость :)
    Думаю, если бы существовало хорошее переносимое решение, оно бы уже было включено в компиляторы.
     
  13. Nafanya

    Nafanya Member

    Публикаций:
    0
    Регистрация:
    26 июл 2006
    Сообщения:
    581
    GRRRLPower
    Можно поподробнее...
     
  14. GRRRLPower

    GRRRLPower New Member

    Публикаций:
    0
    Регистрация:
    17 авг 2010
    Сообщения:
    46
    Если Вы сами задали вопрос про размер экземпляра пустого класса, подразумевается, что Вы знаете ответ)
    А если нет - в поисковиках достаточно ответов.
     
  15. bug1z

    bug1z New Member

    Публикаций:
    0
    Регистрация:
    27 дек 2008
    Сообщения:
    228
    Уже обсуждалось.

    http://wasm.ru/forum/viewtopic.php?id=39868
     
  16. Nafanya

    Nafanya Member

    Публикаций:
    0
    Регистрация:
    26 июл 2006
    Сообщения:
    581
    GRRRLPower
    Но несмотря на найденные Вами недочеты в том участке кода, он кроссплатформенный и тестировался под тремя осями Windows (VS), Linux(KDevelop) и ОСРВ QNX (QNX Momentics IDE). А оптимизация участков кода относящихся к ядру позволила снизить время обработки одной отметки втрое - с 1,5 ms до 428 us. (Информация снята с QNX Application Profiler)
     
  17. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.330
    как интерфейс функции может быть неизвестен на этапе компиляции? пример будьте добры...

    я помню втирал кому-то уже на эту тему... основной смысл в том, что по стандарту sizeof(..) > 0... сообщение #6:
    да... ва_листы...

    +1... именно поэтому надо рассматривать практическую составляющую, а не теоретическую... я помню как то раз ответил что-то вроде: "зачем мне знать алгоритм сортировки пузырьком, если я могу за минуту его нагуглить"...
     
  18. GRRRLPower

    GRRRLPower New Member

    Публикаций:
    0
    Регистрация:
    17 авг 2010
    Сообщения:
    46
    Если бы Вы еще знали такую практическую составляющую, что создавать объекты на стеке во много раз быстрее, чем в куче, думаю, снизили бы еще...

    Быть может, если функция extern? Вроде того:
    main.c:
    Код (Text):
    1. #include <stdio.h>
    2.  
    3. extern int func(); //Только линковщик может найти эту функцию, но не компилятор
    4.  
    5. int main(void)
    6. {
    7.     int a = 2, b = 3;
    8.  
    9.     printf("%u + %u = %u", a, b, func(a, b));
    10.  
    11.     return 0;
    12. }
    func.c:
    Код (Text):
    1. int func(int a, int b)
    2. {
    3.     return a + b;
    4. }
    Но они требуют наличия хотя бы одного формального параметра у функции
     
  19. Nafanya

    Nafanya Member

    Публикаций:
    0
    Регистрация:
    26 июл 2006
    Сообщения:
    581
    Rel
    Например вычисление факториала 5.
    Код (Text):
    1. #include <intrin.h>
    2. #include <stdarg.h>
    3. #include <stdio.h>
    4. int func()
    5. {
    6. va_list vl;
    7. int i;
    8. int arg,Z=1;
    9. va_start(vl,*(int *)_AddressOfReturnAddress());
    10. for(i=0;i<5;i++)
    11.     {
    12.          arg=va_arg(vl,int);   
    13.          Z=arg*Z;
    14.     }
    15.  return(Z);
    16. }
    17.  
    18. int main(void)
    19. {
    20. printf("%d",func(1,2,3,4,5));
    21. getchar();
    22. return 0;
    23. }
    Интересно если скомпилить для x64 то (int *) ,будет указателем на 32-бита или 64-бита?

    GRRRLPower
    Почему Вы не связываете main.c и func.c через h-ник?
     
  20. GRRRLPower

    GRRRLPower New Member

    Публикаций:
    0
    Регистрация:
    17 авг 2010
    Сообщения:
    46
    Только не пишите такое вычисление факториала где-нибудь на собеседовании... И про _AddressOfReturnAddress уже говорили, что не переносим не то что между системами, а даже между компиляторами.

    Ну вот, значит Вы еще и об extern не знаете... Уже и недостаток теоретических знаний проявляется)