The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

форумы  помощь  поиск  регистрация  майллист  ВХОД  слежка  RSS
"Локальные метки в C/C++ от gcc/g++"
Вариант для распечатки Архивированная нить - только для чтения! 
Пред. тема | След. тема 
Форумы Программирование под UNIX (Public)
Изначальное сообщение [Проследить за развитием треда]

"Локальные метки в C/C++ от gcc/g++"
Сообщение от Serega_S emailИскать по авторуВ закладки(ok) on 04-Июл-04, 11:20  (MSK)
   Жуть такая - стыдно-то как! :-) И всё же... Люди! Подскажите как обозначають локальные метки в процедуре? Напомню - это для того, чтобы они были невидимы из других попрограмм. Насколько мне не изменяет память такое было в TASM и быдо это @@имя_метки. Как говорят goto - это зло, но мне кажется глупым использовать какие-то вещи в разрез оптимизации... Хотя конечно во всём должна быть мера... :-)))

                                 С уважением, Сергей.

  Рекомендовать в FAQ | Cообщить модератору | Наверх

 Оглавление

Индекс форумов | Темы | Пред. тема | След. тема
Сообщения по теме

1. "Локальные метки в C/C++ от gcc/g++"
Сообщение от fefelov Искать по авторуВ закладки(??) on 04-Июл-04, 23:17  (MSK)
А вы никакую книжку по C не пробовали читать? Например, Кернигана и Ричи (http://lib.ru/CTOTOR/kernigan.txt)?
Если нет, то попробуйте. Обратите внимание на области действия идентификаторов.
  Рекомендовать в FAQ | Cообщить модератору | Наверх

2. "Локальные метки в C/C++ от gcc/g++"
Сообщение от Serega_S emailИскать по авторуВ закладки(ok) on 05-Июл-04, 06:07  (MSK)
>А вы никакую книжку по C не пробовали читать? Например, Кернигана и
>Ричи (http://lib.ru/CTOTOR/kernigan.txt)?
>Если нет, то попробуйте. Обратите внимание на области действия идентификаторов.
По тому и стыдно было... :-) Вот. Чем не пользовался практически никогда - того и не знаю. А тут вот понадобилось. Спасибо за совет!
  Рекомендовать в FAQ | Cообщить модератору | Наверх

3. "Локальные метки в C/C++ от gcc/g++"
Сообщение от dimus Искать по авторуВ закладки(ok) on 12-Июл-04, 12:45  (MSK)
Не представляю, зачем они тебе нужны. Но синтаксис такой:
void func( void )
{
    goto mylabel
    fputs( "goto - must die!!!\n", stdout );
mylabel:
    fputs( "use assembler for low-level optimization\n" );
}
  Рекомендовать в FAQ | Cообщить модератору | Наверх

4. "Локальные метки в C/C++ от gcc/g++"
Сообщение от Serega_S emailИскать по авторуВ закладки(ok) on 13-Июл-04, 03:14  (MSK)
>Не представляю, зачем они тебе нужны. Но синтаксис такой:
>void func( void )
>{
>    goto mylabel
>    fputs( "goto - must die!!!\n", stdout );
>mylabel:
>    fputs( "use assembler for low-level optimization\n" );
>}

Я бы код показал, но у меня винт умер и всё с ним прихватил... А вообще реально бывают ситуации, где зачастую приходится извращаться (к примеру на работе в коде я много этих извращений видел), извращения наподибии:

do
{
   if(...)break;
...
   if(...)break;

}while(0);

Или (вспомнил свой код):
thread_func()
{
    ...
    if(ошибка)goto exit;
    if(ошибка)goto exit;


   return 0;
exit:
   // Освобождение ресурсов
   ...
   return -1;
}
А так бы пришлось освобождать ресурсы в каждом ифе или извращаться с do-while. Не знаю, но по-моему это как-то неправильно, хотя может быть с какой-то стороны и более читабельно (хотя не всегда, т.к. бывают такие условия, с такой вложенностью... Что в этих скобках фигурных путаешься!). А если допускать не более 2-3-х меток, то можно даже и более читабельным код сделать.
   Не даром Си отражение своего рода ассемблера, а там джамп - одна из основных по сути команд. И зачастую она бывает удобней (хоть и редко, но бывают случаи) чем ворох извратов, которые делают люди лишь бы не использовать безусловный переход, тобишь goto.
Вот так.

                                Сергей.

  Рекомендовать в FAQ | Cообщить модератору | Наверх

5. "Локальные метки в C/C++ от gcc/g++"
Сообщение от dimus Искать по авторуВ закладки(ok) on 20-Июл-04, 09:18  (MSK)
Великолепные по скорости результаты можно получить вообще без меток. Я могу допустить некоторые неточности в синтаксисе - заранее извините

// 1. Определяем прототип - указатель на функцию обработки
typedef FHANDLER void *myhandler( void ); /* указатель на функцию - постоянно забываю правильный синтаксис и каждый раз роюсь в его поисках :), так что здесь скорее всего ошибка*/

// 2. Создаем массив таких указателей
FHANDLER handler[ MAX_HANDLER ];

// Очень быстрый аналог switch( id )
// 3. В цикле
FHANDLER func;
while( 1 )
{
  // Получим адрес нужного обработчика
  func = handler[ <номер нужного обработчика> ];
  // Вызываем обработчик
  func();
  // По моему можно и так: handler[ ID ](); но точно не помню
}

Подобная конструкция прекрасно работает также в качестве конечного
автомата. Главное достоинство - получается очень компактный машинный код и время вызова НЕ ЗАВИСИТ от того, как далеко от начала располагается функция в отличии от конструкций типа switch() или if() Также можно на лету менять
адреса обработчиков и тем самым изменять логику обработки.
Недостатки - требуется, чтобы идентификаторы функций были
более менее непрерывные, иначе будут очень большие затраты памяти

  Рекомендовать в FAQ | Cообщить модератору | Наверх

6. "Локальные метки в C/C++ от gcc/g++"
Сообщение от klalafuda emailИскать по авторуВ закладки on 20-Июл-04, 09:27  (MSK)
>Великолепные по скорости результаты можно получить вообще без меток. Я могу допустить
>некоторые неточности в синтаксисе - заранее извините
>
>// 1. Определяем прототип - указатель на функцию обработки
>typedef FHANDLER void *myhandler( void ); /* указатель на функцию - постоянно
>забываю правильный синтаксис и каждый раз роюсь в его поисках :),
>так что здесь скорее всего ошибка*/
>
>// 2. Создаем массив таких указателей
>FHANDLER handler[ MAX_HANDLER ];
>
>// Очень быстрый аналог switch( id )
>// 3. В цикле
>FHANDLER func;
>while( 1 )
>{
>  // Получим адрес нужного обработчика
>  func = handler[ <номер нужного обработчика> ];
>  // Вызываем обработчик
>  func();
>  // По моему можно и так: handler[ ID ](); но
>точно не помню
>}
>
>Подобная конструкция прекрасно работает также в качестве конечного
>автомата. Главное достоинство - получается очень компактный машинный код и время вызова
>НЕ ЗАВИСИТ от того, как далеко от начала располагается функция в
>отличии от конструкций типа switch() или if() Также можно на лету
>менять
>адреса обработчиков и тем самым изменять логику обработки.
>Недостатки - требуется, чтобы идентификаторы функций были
>более менее непрерывные, иначе будут очень большие затраты памяти

грамотный компилятор и так преобразует switch в таблицу переходов. по возможности конечно.

// wbr

  Рекомендовать в FAQ | Cообщить модератору | Наверх

7. "Локальные метки в C/C++ от gcc/g++"
Сообщение от dimus Искать по авторуВ закладки(ok) on 20-Июл-04, 10:41  (MSK)
Что-то я у компиляторов особой грамотности не видел. Лучший код, который мне довелось увидеть, рожал OpenWatcom Compiler. И gcc тоже довольно неплох, если оптимизацию включить. Но приведенный выше способ не только создает таблицу переходов. Он позволяет выполнять оптимизацию на более высоком уровне. Ведь не даром говорится: Сначала оптимизируй алгоритм, потом код, а потом уже хватайся за ассемблер :) Компилятор тупой, и алгоритм оптимизировать не может. Ты, wbr, просто не разглядел ВСЕХ возможностей данного подхода. Представь себе switch, который меняется в процессе выполнения программы, подстраиваясь под оптимальный вариант работы.
  Рекомендовать в FAQ | Cообщить модератору | Наверх

8. "Локальные метки в C/C++ от gcc/g++"
Сообщение от klalafuda emailИскать по авторуВ закладки on 20-Июл-04, 10:57  (MSK)
>Что-то я у компиляторов особой грамотности не видел. Лучший код, который мне
>довелось увидеть, рожал OpenWatcom Compiler. И gcc тоже довольно неплох, если
>оптимизацию включить.

watcom, bcc, msvc, intel c, gcc и далее по списку

все приличные C компиляторы с которыми я так или иначе работал были в курсе, как оптимизировать switch и как разложить его в таблицу переходов. кто-то делал это лучше кто-то хуже но это уже частности.

> Но приведенный выше способ не только создает таблицу переходов.
>Он позволяет выполнять оптимизацию на более высоком уровне.

неплохо бы туда еще добавить проверку на выход индекса за пределы массива

> Ведь не даром
>говорится: Сначала оптимизируй алгоритм, потом код, а потом уже хватайся за
>ассемблер :) Компилятор тупой, и алгоритм оптимизировать не может.
> Ты, wbr, просто не разглядел ВСЕХ возможностей данного подхода.

я старался, но ничего кроме тривиальной таблицы переходов пока что не увидел. что конечно нисколько не умаляет ее полезность.

> Представь себе switch, который меняется в процессе выполнения
> программы, подстраиваясь под оптимальный вариант работы.

можно пример ?

ps: wbr == with best regards

// wbr

  Рекомендовать в FAQ | Cообщить модератору | Наверх

9. "Локальные метки в C/C++ от gcc/g++"
Сообщение от dimus Искать по авторуВ закладки(ok) on 20-Июл-04, 12:20  (MSK)
Несколько лет назад я делал тестовую программулину, и не уверен, что она сохранилась, но поискать попробую. Это было что-то вроде парсера строки вида
команда1 значение1 ... значениеН команда2 значение1 ... значениеН
У команд были разные значения, т.е. получалось что-то типа программы. Была функция, выделявшая команду (они были однобайтные, так что это было легко :) ) и менявшая адреса в таблице переходов для того, чтобы значения обрабатывались соответствующим образом. Вообще, я хотел сделать что-то типа виртуальной машины, со своим виртуальным машинным кодом. Я реализовал несколько команд (точно помню, что там были nop, сложение и вычитание :) ) а потом потерял к программулине интерес. Где она сейчас - не помню. Но под отладчиком все работало очень даже ничего.
А проверка индекса - это само собой! Это в первую очередь! Кстати, если массив имеет размер 2^n, где n 0 - 31, то зачастую можно просто рубить
лишние биты оператором AND, например:  index = index & 0xF отрубит все, что
после 15
С наилучшими пожеланиями, dimus
  Рекомендовать в FAQ | Cообщить модератору | Наверх

10. "Локальные метки в C/C++ от gcc/g++"
Сообщение от klalafuda emailИскать по авторуВ закладки on 20-Июл-04, 12:25  (MSK)
>А проверка индекса - это само собой! Это в первую очередь! Кстати,
>если массив имеет размер 2^n, где n 0 - 31, то
>зачастую можно просто рубить
>лишние биты оператором AND, например:  index = index & 0xF отрубит
>все, что после 15

и вас не смущает, что при таком подходе молчаливо теряются незапланированные логикой машины состояний варианты ? :) таки обработка default: в switch существует не просто так.

// wbr

  Рекомендовать в FAQ | Cообщить модератору | Наверх

11. "Локальные метки в C/C++ от gcc/g++"
Сообщение от dimus Искать по авторуВ закладки(ok) on 23-Июл-04, 13:35  (MSK)
Нисколько не смущает, так как ничего не теряется. Естественно, этот
подход возможен _не_везде_и_не_всегда_. Но, допустим, мы заранее знаем,
сколько у нас вариантов выбора - тогда грех не использовать преимущества
более скоростного подхода. А если речь идет не про switch, а про обычный
массив? Скомпилируй исходный код и сравни, что получится. Представь, что
такая проверка идет в БОЛЬШОМ цикле.

#define MAX_ARRAY 256

int my_array[ MAX_ARRAY ];

void test_func1( unsigned int index )
{

if( index < MAX_ARRAY )
{
   // Делаем что-то очень полезное  
}

}

// Версия, оптимизированная под массив, размер которого 2 в какой-то
// степени. К сожалению, этот фокус получается редко
void test_func2( unsigned int index )
{
  index = index & 0xFF;
  // Далее делаем что-то полезное
}
Сравните машинный код.
Рекомендую Вам также попробовать на практике то, про что я писал выше.
Может быть тогда Вы лучше меня поймете. Кстати, если я использую таблицу
переходов, то по умолчанию инициализирую ее какой либо функцией-заглушкой,
дабы не было мучительно больно из-за перехода хрен знает куда. Эта функция и есть аналог default в switch.

  Рекомендовать в FAQ | Cообщить модератору | Наверх

12. "Локальные метки в C/C++ от gcc/g++"
Сообщение от klalafuda emailИскать по авторуВ закладки on 23-Июл-04, 14:13  (MSK)
>Нисколько не смущает, так как ничего не теряется. Естественно, этот
>подход возможен _не_везде_и_не_всегда_. Но, допустим, мы заранее знаем,
>сколько у нас вариантов выбора - тогда грех не использовать преимущества
>более скоростного подхода.

видимо, я как-то не так выразился.

при index &= mask; value = array[index]; ошибка выхода индекса за границы массива игнорируется. да, вы не получите SIGSEGV, ибо последующее обращение к массиву будет корректным. но вы не избавляетесь от ошибки выхода индекса за границу массива, вы ее просто отбрасываете.

в случае с if (index >= MAX_VALUE) уже вам решать что делать: игнорировать ошибку, обрабатывать ее или еще что-то.

> А если речь идет не про switch, а про
>обычный массив? Скомпилируй исходный код и сравни, что получится. Представь, что
>такая проверка идет в БОЛЬШОМ цикле.
>
>#define MAX_ARRAY 256
>
>int my_array[ MAX_ARRAY ];
>
>void test_func1( unsigned int index )
>{
>
> if( index < MAX_ARRAY )
> {
>   // Делаем что-то очень полезное
> }
>
>}
>
>// Версия, оптимизированная под массив, размер которого 2 в какой-то
>// степени. К сожалению, этот фокус получается редко
>void test_func2( unsigned int index )
>{
>  index = index & 0xFF;
>  // Далее делаем что-то полезное
>}
>Сравните машинный код.

foo2_:          cmp     eax,00000100H
                jae     short L9

foo3_:          and     eax,000000ffH

это конечно же принципиальная разница с точки зрения производительности.. а вот с точки зрения логики работы программы - да, принципиальная.

>Рекомендую Вам также попробовать на практике то, про что я писал выше.

таблицу переходов ? каждый день использую как минимум неявным образом..

void
foo(int val)
{
        switch (val) {
        case 0 :
                printf("Value 0\n");
                break;
        case 1 :
                printf("Value 1\n");
                break;
        case 2 :
                printf("Value 2\n");
                break;
        case 5 :
                printf("Value 5\n");
                break;
        case 8 :
                printf("Value 8\n");
                break;
        default :
                printf("Invalid value\n");
                break;
        }
}

L1              DD      L2
                DD      L3
                DD      L4
                DD      L7
                DD      L7
                DD      L5
                DD      L7
                DD      L7
                DD      L6
foo_:           cmp     eax,00000008H
                ja      short L7
                jmp     dword ptr cs:L1[eax*4]
L2:             push    offset DGROUP:L10
                jmp     short L8
L3:             push    offset DGROUP:L11
                jmp     short L8
L4:             push    offset DGROUP:L12
                jmp     short L8
L5:             push    offset DGROUP:L13
                jmp     short L8
L6:             push    offset DGROUP:L14
                jmp     short L8
L7:             push    offset DGROUP:L15
L8:             call    near ptr printf_
                add     esp,00000004H
                ret

>Может быть тогда Вы лучше меня поймете.

идея таблицы переходов и так очевидна и прозрачна, я с этим совершенно не спорю :)

> Кстати, если я использую таблицу переходов, то по умолчанию инициализирую ее какой либо функцией-заглушкой,
>дабы не было мучительно больно из-за перехода хрен знает куда. Эта функция
>и есть аналог default в switch.

не совсем. default в switch обрабатывает все значения, не входящие в заданное множество. в то время как заглушка - лишь их подмножество.

// wbr

  Рекомендовать в FAQ | Cообщить модератору | Наверх

13. "Локальные метки в C/C++ от gcc/g++"
Сообщение от vnp emailИскать по авторуВ закладки(??) on 23-Июл-04, 22:46  (MSK)
>Что-то я у компиляторов особой грамотности не видел. Лучший код, который мне
>довелось увидеть, рожал OpenWatcom Compiler. И gcc тоже довольно неплох, если
>оптимизацию включить. Но приведенный выше способ не только создает таблицу переходов.
>Он позволяет выполнять оптимизацию на более высоком уровне. Ведь не даром
>говорится: Сначала оптимизируй алгоритм, потом код, а потом уже хватайся за
>ассемблер :) Компилятор тупой, и алгоритм оптимизировать не может.

Приведенный выше способ есть в натуре оптимизация кода, причем сомнительная. Если учесть накладные расходы на вызов функции (передача параметров, call/jsr, пролог, эпилог, ret, очистка стека) и array fetch, то switch выигрывает по всем пунктам. Особенно если функции короткие, типа "nop, сложение и вычитание :)"

Второй недостаток (вернее сказать, ограничение) подхода -- типизация обработчиков. У всех у них должна быть одна и та же сигнатура, и чтобы достичь настоящей гибкости (и при этом избежать глобалов и/или вариадических функций), приходится стоять на ушах.


>Ты, wbr, просто не разглядел ВСЕХ возможностей данного подхода. Представь себе switch, который
>меняется в процессе выполнения программы, подстраиваясь под оптимальный вариант работы.

Этого, разумеется, switch не умеет. Но место такой технике -- в аду, где грешные программисты вечно отлаживают самомодифицируюшийся код. В свое время люди переписывали jump target address непосредственно в инструкции, по ходу работы программы. Еще быстрее получалось...

  Рекомендовать в FAQ | Cообщить модератору | Наверх

14. "Локальные метки в C/C++ от gcc/g++"
Сообщение от dimus emailИскать по авторуВ закладки(ok) on 27-Июл-04, 13:04  (MSK)
Я тоже писал самомодифицирующийся код. И в ад до сих пор не попал :) Уважаемые критики! Плохо, когда люди читают поверхностно. Я везде указывал, что такой подход применим далеко не всегда, но этот момент Вы как-то пропустили. Ну это уже Ваши проблемы. Как сказал один уважаемый чел, имеющие уши да услышат. Я прекращаю обсуждение этой темы.
С уважением, dimus
  Рекомендовать в FAQ | Cообщить модератору | Наверх


Удалить

Индекс форумов | Темы | Пред. тема | След. тема
Пожалуйста, прежде чем написать сообщение, ознакомьтесь с данными рекомендациями.




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2025 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру