Кодерские tips and tricks

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by TaNkist, 16 Nov 2006.

  1. DWORD

    DWORD Elder - Старейшина

    Joined:
    24 Jul 2007
    Messages:
    129
    Likes Received:
    70
    Reputations:
    -36
    Да, я имел ввиду консольные приложения (или оконные с использованием каких-то кроссплатформенных (всмысле наличия вариантов аналогичной библиотеки для разных платформ с предоставлением программистам аналогичных пограммных интерфейсов) библиотек, если такие существуют, я просто не знаю), пишущиеся в соответствии со стандартом.
     
    #41 DWORD, 2 Nov 2007
    Last edited: 2 Nov 2007
    1 person likes this.
  2. Ky3bMu4

    Ky3bMu4 Elder - Старейшина

    Joined:
    3 Feb 2007
    Messages:
    487
    Likes Received:
    284
    Reputations:
    42
    Скажи нет псевдокоду!
    Code:
    http://algolist.manual.ru/search/esearch/
    
     
    1 person likes this.
  3. Jes

    Jes Elder - Старейшина

    Joined:
    16 Apr 2007
    Messages:
    370
    Likes Received:
    391
    Reputations:
    34
    eazy Сниф порта

    В Делфи чтобы просушать уже открытый порт достаточно взять компонент IdTCP из вкладки Indy clients , в bound port пишешь свой порт и обрабатываешь событие чтения.
     
  4. A2GIL

    A2GIL Elder - Старейшина

    Joined:
    31 Aug 2007
    Messages:
    84
    Likes Received:
    59
    Reputations:
    -3
    Delphi

    Для тех, кому важен размер программы. Иногда требуется что либо сделать по таймеру, тут уже стандартным компонентом Timer не обойтись, тогда воспользуемся следующими функциями:

    Code:
    [COLOR=DarkOrange]uses MMSystem[/COLOR] [COLOR=Cyan]///подключим необходимый модуль[/COLOR]
    ...
    var
     
     TID:Integer;
    ...
    
    procedure TimeCallback(TimerID, Msg : UINT; DWUser,DW1,DW2 : DWord); pascal;
    
    [COLOR=Cyan]///сюда вставляем код, который должен выполняться по таймеру[/COLOR]
    
    end;
    
    procedure StartTimer(interval:cardinal);
    begin
     TID := timeSetEvent(interval,0,@TimeCallBack,0,TIME_PERIODIC);
    end;
    
    
    
    [COLOR=Cyan]//используем нашу процедуру[/COLOR]
    
    StartTimer(10000)  [COLOR=Cyan]// то есть 10 секунд[/COLOR]
     
    1 person likes this.
  5. x0man

    x0man Elder - Старейшина

    Joined:
    24 Feb 2006
    Messages:
    33
    Likes Received:
    13
    Reputations:
    0
    не знаю откуда это вообще взялось... мб старые компилеры такую хрень делали,
    не знаю, не смотрел, но явно не в 7-й делфе...
    [​IMG]
    Пис!
     
    1 person likes this.
  6. desTiny

    desTiny Elder - Старейшина

    Joined:
    4 Feb 2007
    Messages:
    1,006
    Likes Received:
    444
    Reputations:
    94
    Delphi - простая работа с файлами

    Часто в коде программ можно увидеть что-то типа
    Code:
    var
      fi, fo: file;
      a: integer;
    ..
    assignfile(fi, 'a.in');
    reset(fi);
    assignfile(fo, 'a.out');
    rewrite(fo);
    read(fi, a);
    write(fo, a);
    close(fi);
    close(fo);
    Реже встречается код, когда работа идёт с переопределением стандартного ввода/вывода, что на самом деле удобнее, поскольку в write, read, writeln и readln не надо писать ссылку на файл:
    Code:
    var
      a: integer;
    ..
    assignfile(input, 'a.in');
    reset(input);
    assignfile(output, 'a.out');
    rewrite(output);
    read(a);
    write(a);
    close(input);
    close(output);
    На самом деле - можно сделать ещё короче:
    Code:
    var
      a: integer;
    ..
    reset(input, 'a.in');
    rewrite(output, 'a.out');
    read(a);
    write(a);
    close(input);
    close(output);
    Кстати (тестилось и на винде, и на никсах - везде результат положительный), можно даже и не использовать
    - система сама всё правильно закрывает.
     
  7. x0man

    x0man Elder - Старейшина

    Joined:
    24 Feb 2006
    Messages:
    33
    Likes Received:
    13
    Reputations:
    0
    Если так рассуждать, то вообще и память освобождать не надо и дескрипторы закрывать... конечно система сама всё закроет и поудаляет всё что надо, но это показывает, что у программиста руки из жопы растут... так что пишите красивый код или по крайней мере по правилам хорошего тона... а не через задницу...
     
  8. desTiny

    desTiny Elder - Старейшина

    Joined:
    4 Feb 2007
    Messages:
    1,006
    Likes Received:
    444
    Reputations:
    94
    Я и не говорю, что так надо делать - я говорю, что это не критично. Просто, если открывать всё через CreateFile, то тогда, если не закрыть, то произойдёт что-нибудь нехорошее...
    Сам я вообще стремлюсь к чему-то такому:

    Code:
    var
      a: integer;
    ..
    reset(input, 'a.in');
    rewrite(output, 'a.out');
    try
      read(a);
      write(a);
    finally
      close(input);
      close(output);
    end;
    
    PS Везёт мне на красивые номера постов сейчас :) Этот - 666777 :)
     
  9. x0man

    x0man Elder - Старейшина

    Joined:
    24 Feb 2006
    Messages:
    33
    Likes Received:
    13
    Reputations:
    0
    стремиться надо вот к такому если оперировать с файлами функциями делфы...
    Code:
    var input : File;
    begin
      AssignFile(input, 'a.txt');
      {$I-}
        Reset(input);
      {$I+}
      if IOResult <> 0 then exit;
      CloseFile(input);
    end;
    
     
  10. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    Довольно интерестный способ вызова API функций. Очень удобен в случаях низко уровнего программирования или в тех местах где очень важен размер.
    Многие API функции из kernel32.dll имеют аналоги в ntdll которые в свою очередь это лишь только оболочка над ядерными функциияви вызываемыми через SYSENTER
    Вот примера вызова определенной функции напрямую через SYSENTER => нам даже не нужен импорт. Разви что зависимость от операционной системы.
    Данный пример - аналог функции VirtualProtect для XP
    Code:
     
     push _start	  ; адрес начала блока
     mov eax,esp	  ; eax = Pstart_block
     push 100	  ; длинна блока
     mov edx,esp	  ; edx = Plength_block
     push esp	  ; для нас не важно
     push 4 	  ; новые права доступа
     push edx	  ; Plength_block
     push eax	  ; Pstart_block
     push -1	  ; говорит что это наш процес
     xor eax,eax	  ;
     mov al,89h	  ; eax=89h => NtProtectVirtualMemory для XP
     push eax	  ; в нашем случае не важно что тут
     push @m1	  ; куда попадем после SYSENTER
     mov edx, esp	  ; нуна для SYSENTER
     sysenter
    @m1:
     add esp,20h	  ; Очищаем стек
    
     
    1 person likes this.
  11. Dober'man

    Dober'man Banned

    Joined:
    16 Jul 2007
    Messages:
    70
    Likes Received:
    94
    Reputations:
    -8
    Точим exploit
    Разбор ошибок выдаваемых компилятором gcc при попытке трансляции файла beta.cpp​


    Исходник - http://milw0rm.com/shellcode/656
    Часть исходника:
    Code:
    #include <stdio.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #include <malloc.h>
    #include <string.h>
    #include <windows.h>
    
    #define MAX_BUFFER_SIZE 0x1000
    #define DEFAULT_PAD_BYTE 0x90
    #define MAX_MARKER_SIZE 0x10
    #define bool char
    #define true 1
    #define false 0
    
    char* hex = "0123456789abcdef";
    
    void version(void) {
        printf(
            "______________________________________________________________________________\n"
            "\n"
            "     ,sSSSis   ,sSSSs,   Beta v2.0.\n"
            "    iS\"   dP  dY\"  ,SP   Encodes binary data to/from a variety of formats.\n"
            "   .SP dSS\"      ,sS\"    Copyright (C) 2003-2005 by Berend-Jan Wever\n"
            "   dS'   Sb    ,sY\"      <[email protected]>\n"
            "  .SP dSSP'  sSSSSSSP    http://spaces.msn.com/members/berendjanwever\n"
            "_ iS:_________________________________________________________________________\n"
            "\n"
        );
      return;
    }
    void help(void) {
        printf(
            "Beta was developed to convert raw binary shellcode into text that can be\n"
            "used in exploit source-code. It can convert raw binary data to a large\n"
            "number of encodings.\n"
    		"\n"
            "  Usage: BETA [options] [input file name]\n"
    		"\n"
            "  input file name           Read input from the given file. By default BETA\n"
            "                            reads input from stdin.\n"
    		"\n"
            "General options:\n"
            "  --help                    Display this help and exit\n"
            "  --version                 Output version information and exit\n"
            "  --verbose                 Displays additional information.\n"
            "  --pause                   Wait for keypress before exiting.\n"
    		"\n"
    		"Encoding options: (default = AA BB CC ...)\n"
            "  \\x                        \\xAA\\xBB\\xCC ...\n"
            "  0x                        0xAA 0xBB 0xCC ...\n"
            "  %%                         %%AA%%BB%%CC...\n"
            "  #                         oÞ!...\n"
            "  %%u                        %%uBBAA%%uDDCC...\n"
            "  --noencode                Don't encode (only do checks).\n"
    		"\n"
            "Layout options: (default = none)\n"
            "  --chars/line=X            Output a new line after every X encoded bytes.\n"
            "  --quotes                  Wrap output in quotes. Only usefull in combination\n"
            "                            with chars/line argument.\n"
            "  --quotesplus              Wrap output in quotes and add a '+' at the end\n"
            "                            of each line. Only usefull in combination with\n"
            "                            chars/line argument.\n"
            "  --spaces                  Seperate encoding entities by spaces.\n"
            "  --commas                  Seperate encoding entities by commas and spaces.\n"
    		"\n"
    		"Additional options:\n"
    		"  --padbyte=AA              When using a multibyte encoding (e.g. %%uXXXX)\n"
    		"                            the data might need some padding. The given byte\n"
    		"                            will be used, the default value is %02x.\n"
    		"  --badbytes[=AA[,BB[...]]] Check the input for presence of the given char-\n"
    		"                            acters and report where they are found. You can\n"
    		"                            supply a comma seperated list of hexadecimal\n"
    		"                            character codes and the keywords \"alpha\" and\n"
    		"                            \"print\" (to check for the presence of nonalpha-\n"
    		"                            numeric or non-printable characters). If no char-\n"
    		"                            acters are supplied, the input will be checked for\n"
    		"                            the presence of 00, 0A and 0D. \n"
            "  --marker[=AA[,BB[...]]]   The input contains both garbage and data. The data\n"
            "                            is wrapped by the marker bytes, everything before\n"
            "                            the first set and after the last set of marker\n"
            "                            bytes will be ignored. If no marker bytes are\n"
            "                            supplied, \"CC CC CC\" (3xInt3) will be used.\n"
            "                            You can supply up to %d bytes as marker.\n",
            DEFAULT_PAD_BYTE, MAX_MARKER_SIZE
        );
      return;
    }
    
    // Find a set of bytes in another set of bytes
    char* find_bytes(char* haystack, int haystack_length, char* needle, int needle_length) {
    	int needle_start = -1, needle_checked = 1;
    	do {
    		if (haystack[needle_start+needle_checked] == needle[needle_checked])
    			// Yes, bytes match, check next byte of needle
    			needle_checked++;
    		else {
    			// No, no match, check next byte of haystack
    			needle_start++;
    			needle_checked = 0;
    		}
    		if (needle_start + needle_length > haystack_length)
    			// Not found.
    			return 0;
    	} while (needle_checked != needle_length);
    	// Found!
    	return haystack + needle_start;
    }
    
    int main(int argc, char** argv, char** envp) {
    
    	// This will contain the input data
    	char* buffer;
    	int buffer_length = 0;
    
    	// This will contain the marker
    	char marker[MAX_MARKER_SIZE];
    	int marker_length = 0;
    
    	// This will keep track of all "bad" bytes
    	char char_is_bad[0x100];
        for (int i = 0; i < sizeof(char_is_bad)/sizeof(*char_is_bad); i++)
        	char_is_bad[i] = false;
    
    	// These will store some values supplied by command line arguments
    	bool switch_verbose = false, switch_encode = true, switch_pause = false;
    	char pad_byte = DEFAULT_PAD_BYTE;
        int chars_per_line = -1;
        char *input_filename = 0;
        char *line_header = "", *line_footer = "\n", *footer = "\n";
        char *bytes_format = "%02X", *byte_seperator = "";
        int bytes = 1;
    
    	//--------------------------------------------------------------------------
    	// Read and handle arguments
        for (int argn = 1; argn < argc; argn++) {
    		//--help ---------------------------------------------------------------
        	if (stricmp(argv[argn], "--help") == 0) {
        		version();
        		help();
    			if (switch_pause) getchar();
        		exit(EXIT_SUCCESS);
    		//--version ------------------------------------------------------------
        	} else if (stricmp(argv[argn], "--version") == 0) {
        		version();
    			if (switch_pause) getchar();
        		exit(EXIT_SUCCESS);
    		//--verbose ------------------------------------------------------------
        	} else if (stricmp(argv[argn], "--verbose") == 0) {
        		switch_verbose = true;
    		//--noencode -----------------------------------------------------------
        	} else if (stricmp(argv[argn], "--noencode") == 0) {
        		switch_encode = false;
    		//--noencode -----------------------------------------------------------
        	} else if (stricmp(argv[argn], "--pause") == 0) {
        		switch_pause = true;
    		//--chars/line= --------------------------------------------------------
    	    } else if (strnicmp(argv[argn], "--chars/line=", 13)==0) {
    	    	if ((chars_per_line = strtol(&(argv[argn][13]), NULL, 10)) < 1) {
    	    		printf("Illegal number of characters per line: \"%s\".\n", &(argv[argn][13]));
    	    		if (switch_pause) getchar();
    	    		exit(EXIT_FAILURE);
    	    	}
    		//--layout options -----------------------------------------------------
    	    } else if (strcmp(argv[argn], "--quote") == 0 || strcmp(argv[argn], "--quotes") == 0) {
    	        line_header = "\"";
    	        line_footer = "\"\n";
    	        footer = "\"\n";
    	    } else if (strcmp(argv[argn], "--quoteplus") == 0 || strcmp(argv[argn], "--quotesplus") == 0) {
    	        line_header = "\"";
    	        line_footer = "\" +\n";
    	        footer = "\"\n";
    	    } else if (strcmp(argv[argn], "--comma") == 0 || strcmp(argv[argn], "--commas") == 0) {
    	        byte_seperator = ", ";
    	    } else if (strcmp(argv[argn], "--space") == 0 || strcmp(argv[argn], "--spaces") == 0) {
    	        byte_seperator = " ";
    		//--encoding options ---------------------------------------------------
    	    } else if (stricmp(argv[argn], "\\x")==0) {
    	    	bytes_format = "\\x%02X";
    	    } else if (stricmp(argv[argn], "0x")==0) {
    	    	bytes_format = "0x%02X";
    	    } else if (stricmp(argv[argn], "#")==0) {
    	    	bytes_format = "&#%d;";
    	    } else if (stricmp(argv[argn], "%")==0) {
    	    	bytes_format = "%%%02X";
    	    } else if (stricmp(argv[argn], "%u")==0) {
    	    	bytes_format = "%%u%04X";
    	    	bytes = 2;
    		//--padbyte ------------------------------------------------------------
    	    } else if (strnicmp(argv[argn], "--padbyte=", 10) == 0) {
    	    	char* next_xarg;
    			pad_byte = strtol(&(argv[argn][10]), &next_xarg, 0x10);
    			if ((pad_byte & 0xFF) != pad_byte) {
    				printf("Incorrect value in padbyte argument: \"%s\".\n", &(argv[argn][11]));
    				printf("  Value cannot be converted to a byte ");
    				for (int i = 0; i < strlen(&(argv[argn][10])); i++)
    					printf("^");
    				printf("\n");
    				if (switch_pause) getchar();
    	    		exit(EXIT_FAILURE);
    			}
    			if (next_xarg == &(argv[argn][10])) {
    				printf("Incorrect byte encoding in padbyte argument: \"%s\".\n", &(argv[argn][10]));
    				if (switch_pause) getchar();
    	    		exit(EXIT_FAILURE);
    			}
    		//--badbytes -----------------------------------------------------------
    		} else if (stricmp(argv[argn], "--badbytes") == 0) {
    			char_is_bad[0x0] = true;
    			char_is_bad[0xA] = true;
    			char_is_bad[0xD] = true;
    		//--badbytes=XX,XX,... -------------------------------------------------
    	    } else if (strnicmp(argv[argn], "--badbytes=", 11) == 0) {
    			char* xarg = &(argv[argn][11]);
    			while (strlen(xarg) > 0) {
    				if (strnicmp(xarg, "alpha", 5) == 0) {
    					for (int i = 0; i < 0x100; i++) {
    						if (!isalnum(i)) char_is_bad[i] = true;
    					}
    					xarg += 5;
    				} else if (strnicmp(xarg, "print", 5) == 0) {
    					for (int i = 0; i < 0x100; i++) {
    						if (!isprint(i)) char_is_bad[i] = true;
    					}
    					xarg += 5;
    				} else {
    					char* next_xarg;
    					int decoded = strtol(xarg, &next_xarg, 0x10);
    					if ((decoded & 0xFF) != decoded) {
    						printf("Incorrect value in badbytes argument: \"%s\".\n", &(argv[argn][11]));
    						for (char* i = &(argv[argn][9]); i < xarg; i++)
    							printf(" ");
    						printf(" Value cannot be converted to a byte ");
    						for (char* i = xarg; i < next_xarg; i++)
    							printf("^");
    						printf("\n");
    						if (switch_pause) getchar();
    			    		exit(EXIT_FAILURE);
    					}
    					if (next_xarg == xarg) {
    						printf("Incorrect byte encoding in badbytes argument: \"%s\".\n", &(argv[argn][11]));
    						for (char* i = &(argv[argn][11]); i < xarg; i++)
    							printf(" ");
    						printf("                    Character '%c' not expected ^\n", *xarg);
    						if (switch_pause) getchar();
    			    		exit(EXIT_FAILURE);
    					}
    					
    					char_is_bad[decoded] = true;
    					xarg = next_xarg;
    				}
    				if (*xarg == ',') xarg++;
    			}
    
    А это список ошибок выдаваемых компилятором(не считая варнигов):
    HTML:
    beta.cpp:34:21: windows.h: No such file or directory
    beta.cpp: In function `int main(int, char**, char**)':
    beta.cpp:165: error: `stricmp' undeclared (first use this function)
    beta.cpp:185: error: `strnicmp' undeclared (first use this function)
    beta.cpp:245: error: `isalnum' undeclared (first use this function)
    beta.cpp:250: error: `isprint' undeclared (first use this function)
    beta.cpp:339: error: invalid conversion from `void*' to `char*'
    beta.cpp:356: error: `O_BINARY' undeclared (first use this function)
    beta.cpp:361: error: `lseek' undeclared (first use this function)
    beta.cpp:377: error: invalid conversion from `void*' to `char*'
    beta.cpp:384: error: `read' undeclared (first use this function)
    beta.cpp:398: error: `close' undeclared (first use this function)
    
    Ну, с ошибкой 34 все понятно — программа усиленно косит под форточки, не понятно за каким хреном таща за собой файл <windows.h>, но тут же использует стандартные POSIX- вызовы: open (со странным флагом O_BINARY), lseek, read и close, которых ни в самом windows, ни в одном из win32-компиляторов никогда не существовало (см. ошибки 356, 361, 384 и 398). Убираем строку "#include <windows.h>", заменяя ее на "#include <unistd.h>" и удаляем глупый флаг O_BINARY, поскольку по умолчанию файл уже является двоичным (узнать какие заголовочные файлы соответствуют данной функции можно из man'а, например, "man 2 open"). Для избавления от ругательства "this file include <malloc.h> witch is deprecated, use <stdlib.h> instead" удаляем и "#include <malloc.h>".
    Ошибки 245 и 250 устраняются подключением их "родного" заголовочного файла, в котором они были объявлены "#include <ctype.h>" (см. "man isalnum"). А вот функций stricmp и strnicmp в gcc действительно нет, однако, они могут быть заменены на аналогичные им strcmp и strncmp даже без коррекции аргументов!
    Ошибки 339 и 377 исправляется еще проще: достаточно взять строку "buffer=malloc(MAX_BUFFER_SIZE)" и добавить явное преобразование типов, так же называемое ксатингом: "buffer=(char*)malloc(MAX_BUFFER_SIZE)".


    Еще дополню разбором shell-кода, как только воткну в него =)
     
  12. zythar

    zythar Elder - Старейшина

    Joined:
    16 Feb 2008
    Messages:
    517
    Likes Received:
    109
    Reputations:
    5
    может все таки кастом?

    зы кастинг - подбор актеров (*
     
  13. 0verbreaK

    0verbreaK Elder - Старейшина

    Joined:
    30 Apr 2008
    Messages:
    318
    Likes Received:
    42
    Reputations:
    -3
    Вообще зверь. Может нормально отредактируешь точто находится зеленым цветом, вплотную не соблюдая абзацов. И вообще обычное дело доработка эксплоитов, КК писал об этом. В любом случае молодец.
     
  14. SVAROG

    SVAROG Elder - Старейшина

    Joined:
    13 Feb 2007
    Messages:
    424
    Likes Received:
    86
    Reputations:
    -1
    сишные трюки

    сишные трюки
    (1Fh выпуск)



    язык си не предоставляет никаких средств для временного отключения блоков кода и большинство программистов делают это с помощью комментариев. казалось бы что может быть проще и о каких трюках тут вообще говорить? на самом же деле, комментарии не только не единственный, но и едва ли не самый худший прием среди прочих о которых мы сейчас и поговорим!

    трюк #1*– комментарии, ремарки и помарки

    Системы контроля версий как раз и создавались для того, чтобы обеспечить легкий, прозрачный и непротиворечивый механизм безопасной правки исходных текстов инвариантный по отношению к самому языку. Однако, на практике системы контроля версий используются только для организации совместной работы над проектом, да и то не всегда. Уж слишком много телодвижений приходится совершать всякий раз, а программисты*— люди ленивые.
    Если нам необходимо временно отключить блок кода, намного проще закомментировать его, а потом удалить комментарии, подключая его обратно. Быстро. Дешево. Сердито. Но увы… потенциально небезопасно с точки зрения внесения новых ошибок и развала уже отлаженной программы, чего допускать ни в коем случае нельзя. А потому прежде, чем идти дальше, сформулируем перечень требований, предъявляемый к механизмам отключения кода:

    • легкость использования (никто не будет пользовать средство, требующее кучи телодвижений);
    • вложенность (внутри отключаемого блока может находится один или несколько ранее отключенных блоков);
    • многоуровневость (если для отключения блока кода необходимо исправить два и более несмежных фрагментов исходного текста, необходимо гарантировать корректное снятие блокировки, что становится особенно актуально, если отключаются независимые блоки А, B, С*– тогда, при включении блока B возникает угроза подключения фрагментов, относящихся к блокам A и C, что ведет к развалу программы);
    • поддержка всех языковых конструкций (какой прок от инструмента, если он работает только с ограниченным набором языковых конструкций, например, не позволяет отключать ассемблерные вставки?!);
    Удовлетворяют ли комментарии указанным требованиям?! А вот и нет! Комментарии в стиле Си (/* */) очень удобны, поскольку, позволяют отключать огромные блоки кода нажатием всего четырех клавиш, к тому же они могут располагаться в любом месте строки, а не только в ее начале. Однако, отсутствие поддержки вложенности создает серьезные проблемы.
    Например:
    Code:
    /* ошибка! закомментированный блок уже содержит /*   */
    	for (a = 0; a < N; a++)
    	{
    		/*
    			for (b = 0; b < M; b++)
    				if (!strcmp(name_array[a], vip_array[b])) continue;
    		*/
    		
    		// DeleteFile(name_array[a]);
    		pritnf("%d %s\n", a, name_array[a]);
    		
    	}
    */
    
    Листинг*1*демонстрация некорректного использования комментариев /* */ для временного отключения блоков кода​
    [/B]

    Попытка выключить цикл for (a,,) ведет к ошибке компиляции*— комментарии /* */ не могут быть вложенными и в таких случаях программисты используют альтернативу в виде "//" допускающую вложенность, но, увы, вручную проставляемую вначале _каждой_ строки, что очень утомительно и совершенно непроизводительно, если, конечно, не использовать макросы, поддерживаемые средой разработки (а практически все среды разработки их поддерживают). Аналогичным образом осуществляется и снятие комментариев.
    И все было бы хорошо, да вот неоднозначности с уровнем вложенности делают отключение блоков небезопасным. В нашем случае мы имеем три раздельных отключаемых блока кода. Во-первых, это заблокированная проверка принадлежности удаляемого файла к vip_array, во-вторых, это, собственно, само удаление файла (заблокированное и замененное отладочной печатью через printf) и, в-третьих, комментарий, пытающийся отключить цикл for(a,,) со всем что в нем находится.
    Отключаются блоки кода очень просто, а вот обратное утверждение уже неверно. Никаким автоматизмом тут уже и не пахнет, в результате чего нам приходится разбираться с назначением каждого блока самостоятельно. Однако, если немного поколдовать над комментариями…
    Пусть следом за "//" идет цифра (или буква) указывающая принадлежность текущей комментируемой строки к блоку кода. Продвинутые среды разработки типа Microsoft Visual Studio поддерживают развитый макроязык, позволяющий выполнять лексический анализ, удаляя только те комментарии, за которыми идет заданная буква/цифра.
    Это может выглядеть, например, так:
    Code:
    //3	for (a = 0; a < N; a++)
    //3	{
    //3 //2
    //3 //2		for (b = 0; b < M; b++)
    //3 //2			if (!strcmp(name_array[a], vip_array[b])) continue;
    //3 //2
    //3 //1		// DeleteFile(name_array[a]);
    //3		pritnf("%d %s\n", a, name_array[a]);
    //3 	}
    
    Листинг*2*имитация многоуровневой структуры отключаемых блоков исходного кода посредством комментариев​

    Проблема вложенности решена на 100%, проблема многоварианости*— на 50% (после удаления комментария //1 мы так же должны удалить, а точнее временно заблокировать следующую за ним строку с отладочной печатью), однако, в целом предложенная техника намного более удобна и единственный серьезный недостаток*— привязка программиста к конкретной среде с набором пользовательских макросов. Менее серьезный недостаток*— ассемблерные вставки как правило не поддерживают Си/Си++ комментариев и потому должны обрабатываться отдельно, усложняя реализацию нашего макродвижка и сводя его преимущества на нет.

    трюк #2*— директивы условной трансляции

    Разработанные для поддержки многовариантного кода директивы условной трансляции оказались практически невостребованными (речь, разумеется, идет только о временном выключении кода), что очень странно*— директивы условной трансляции намного более эффективны, чем комментарии и пример, приведенный ниже, доказывает этот тезис.
    Code:
    #define _D1_		// блок _D1_ включен
    //#define _D2_		// блок _D2_ выключен
    #define _D3_		// блок _D3_ включен
    
    #ifdef _D1_
    	for (a = 0; a < N; a++)
    	{
    
    #ifdef _D2_
    			for (b = 0; b < M; b++)
    				if (!strcmp(name_array[a], vip_array[b])) continue;
    #endif
    
    #ifdef _D3_
    		DeleteFile(name_array[a]);
    #else
    		pritnf("%d %s\n", a, name_array[a]);
    #endif
    	}
    #endif
    
    Листинг*3*директивы препроцессора, отключающие блоки кода​


    Проблема вложенности решается сама собой, многовариантность поддерживается очень хорошо, позволяя нам включать/выключать определенные блоки, не затрагивая остальных, причем, при подключении "DeleteFile(name_array[a])"*— автоматически отключается отладочная печать и наоборот. В результате чего риск развала программы уменьшается до нуля. Самое интересное, что директивы условной трансляции ничуть не хуже работают и с ассемблерными вставками!
    Code:
    __asm{
    	xor eax,eax
    #ifdef _D1_
    	PUSH file_name
    	CALL DeleteFile
    #endif
    }
    
    Листинг*4*директивы препроцессора, отключающие ассемблерные инструкции _внутри_ ассемблерных вставок​

    Конечно, писать "#if def _Dx_" намного длиннее, чем "//" или "/* */", однако, это не проблема*— клавиатурные макросы на что?! Хотя про нежелание связаться с макросами мы уже говорили. Ну макросы это ладно. Хуже всего, что отключенные блоки кода не попадают в релиз, и если у конечного пользователя программа начнет дико глючить у нас не будет никакой возможности отключить их без перекомпиляции всего кода.

    трюк #3*– ветвления

    Финальный прием устраняет основные недостатки предыдущего трюка, добавляя к нему свои собственные достоинства, а достоинств у него… Короче, намного больше одного. Идея заключается в использовании конструкции if (_Dx_), а при необходимости и if (_Dx_) else.
    Оператор "if", стоящий перед одиночным блоком кода, не требует замыкающего "#endif", что ускоряет процесс программирования и не так сильно загромождает листинг. Но это мелочь. Гораздо важнее, что если _Dx_ константа (например, "1"), то оптимизирующий компилятор выбрасывает вызов if, удаляя лишний оверхид. Если же _Dx_ переменная (глобальная, конечно), то компилятор оставляет ветвление "как есть", давая нам возможность управлять поведением программы*— если у пользователей возникнут проблемы из-за ошибки в плохо отлаженном блоке кода, то этот блок можно отключить (естественно, если значения флагов вынесены в конфигурационный файл или доступны через пользовательский интерфейс, но это уже несущественные детали реализации).
    Пример использования ветвлений для отключения блоков кода приведен ниже:
    Code:
    #define _D1_	0	// блок _D1_ выключен (ветвление в релиз не попадает)
    #define _D3_	1	// блок _D3_ включен  (ветвление в релиз не попадает)
    int	_D2_	1	// блок _D2_ включен  (ветвление попадает в релиз!)
    
    if (_D1_)
    	for (a = 0; a < N; a++)
    	{
    	
    if (_D2_)
    	for (b = 0; b < M; b++)
    			if (!strcmp(name_array[a], vip_array[b])) continue;
    if (_D3_)
    		DeleteFile(name_array[a]);
    else
    		pritnf("%d %s\n", a, name_array[a]);
    	}
    
    Листинг*5*использование ветвлений для выключения блоков кода​

    Как мы видим, листинг*5 намного компактнее и нагляднее листинга*4, так что при всем уважении к директивам условной трансляции, они идут лесом. А вот ветвления можно использовать для выключения блока ассемблерных вставок (о чем кстати говоря, умалчивает штатная документация, но следующий пример компилируется вполне нормально):
    Code:
    #define _D1_	0
    
    if (_D1_)
    	__asm{
    		INT 03
    	}
    
    Листинг*6*использование ветвлений для выключения ассемблерных вставок​

    Ветвления, конечно, тоже не лишены недостатков, однако, для временного выключения блоков кода они намного лучше, удобнее и продуктивнее, чем комментарии. Естественно, существуют и другие средства. Взять хотя бы "return", позволяющий одним движением руки погасить блок кода до самого конца функции. Критикуемый GOTO*– отличная штука, но только в малых дозах. Иначе программа превращается в настоящее спагетти, которое практически невозможно распутать.

    (c)крис касперски ака мыщъх, a.k.a. souriz, a.k.a. nezumi, no-email
     
    3 people like this.
  15. Chaak

    Chaak Elder - Старейшина

    Joined:
    1 Jun 2008
    Messages:
    1,059
    Likes Received:
    1,067
    Reputations:
    80
    Читаю, где-то я это читал - Крис Касперски - понятно .(напишите его имя в копирайтах с заглавной буквы)

    У кого - нибудь есть ссылки на его статьи по C? Можете поделиться?
     
    #55 Chaak, 20 Mar 2009
    Last edited: 20 Mar 2009
  16. h01der

    h01der New Member

    Joined:
    17 Feb 2009
    Messages:
    12
    Likes Received:
    2
    Reputations:
    0
    #56 h01der, 21 Mar 2009
    Last edited: 21 Mar 2009
  17. De-visible

    De-visible [NDC] Network develope c0ders

    Joined:
    6 Jan 2008
    Messages:
    916
    Likes Received:
    550
    Reputations:
    66
    весь хакер(журнал) забит ими, интересно кстати почитать.
     
  18. h01der

    h01der New Member

    Joined:
    17 Feb 2009
    Messages:
    12
    Likes Received:
    2
    Reputations:
    0
    Ну вот я их выложил в посте выше...