Статьи, заметки, приемы программирования — HackZona.Ru

В этом топе публикуются статьи/заметки либо просто интересные моменты касающиеся программированию. Как всегда стараемся соблюдать орфографию и указываем копирайты.

Статьи, заметки, приемы программирования

Сообщений в теме: 11
Нравится
Не нравится
Репутация: 0
Рейтинг: 1
Кол-во тем: 0
Сообщения: 0

В этом топе публикуются статьи/заметки либо просто интересные моменты касающиеся программированию.
Как всегда стараемся соблюдать орфографию и указываем копирайты.
Нравится
Не нравится
Репутация: 0
Рейтинг: 0
Кол-во тем: 0
Сообщения: 0
Данная заметка — капля в море по сравнению с материалом от --StraNger--,
но надеюсь, что найдутся люди, которым она будет полезна.

Когда начал серьезно работать с javascript и использовать большие библиотеки, то у меня возник вопрос по сжатию кода:
одни пакеры сжимают код путем записи больших обьемов кода в одну строку, а другие сжимают путем уменьшения длинны строки (но строк тогда много)… так какие же форматы будут быстрее и лучше пониматься браузером?
Ответ на этот вопрос:
Строки в длинном формате лучше уменьшают размер файла, но строки длиннее 1024(это очень мало) символов это приводит к проблемам в браузере internet explorer. Поэтому не рекомендую положить весь код в строку длинной 999999999 символов и радоватся уменьшению в размере :P
лучше паковать таким сервисом как например [url]http://shrinksafe.dojotoolkit.org/[/url]

и обращайте внимание на то, в каком формате файл хранит данные:
[URL=«kb.iu.edu/data/acux.html»]How do I convert between Unix and Windows text files[/URL]
Нравится
Не нравится
Репутация: 0
Рейтинг: 1
Кол-во тем: 0
Сообщения: 0
Что бы больше не оставалось вопросов о потоках в дельфи, решил выложить эту статью
Основы работы с потоками в Delphi
Автор: Litex
Привет. Из сегодняшнего примера ты сможешь узнать основы работы с потоками. И начнем мы, пожалуй, с самого определения потока. И так что такое поток? Поток это код, который входит в состав программы, выполняется в её адресном пространстве и использует её (программы) ресурсы. Как ты уже наверно догадался любая программа представляет собой один главный поток и несколько вспомогательных (кстати, вспомогательных может и не быть).

Так вот главная фича в потоках в том, что они могут выполняться почти параллельно (или по научному псевдопараллельно) именно почти, а не совсем. На самом деле настоящая параллельность возможна только на многопроцессорной машине (2 и более проца). Но WiNdoWs, может имитировать такую работу (и не вини её в этом, если винишь, то читай выше) т.е. она (Windoz) для каждого потока выделяет небольшое количество процессорного времени (несколько миллисекунд), по истечению это времени видоус даёт поработать другому потоку потом следующему и так далее. И как ты уже наверно смог догадаться, для каждого потока определен соответствующий приоритет выполнения. Проще говоря, при написание кода мы можем указывать системе как часто она должна выделять потоку процессорного времени. Как это сделать будет рассказано ниже.

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

На этом с теорией пожалуй можно закончить и перейти к самому программировании. Многопоточного программного продукта (программный продукт какое хорошее словосочетание).

Шаг 1. Запускай Delphi (если не знаешь как то это тебе читать еще рановато).

Шаг 2. Создай новое приложение (File->New Application).

Шаг3. На появившеюся форму брось одну кнопку ( у меня это будет Button1) и две области рисования (у меня это будет PaintBox1 и PaintBox2 соответственно{ширина и высота, которых 300}).

Шаг 4. В модуле главной формы опишем новый метод (у меня это будет gtextout), который в качестве параметра будет получать холст и выводить на нем, в произвольном месте, любой символ (у меня это будет @ без кавычек соответственно).

Шаг 4.1. Рассмотрим подробней как выполнить на практике выше указанное действие.

Созда новую процедуру. Впиши procedure gtextout(CNV: TCanvas) перед словом private. Затем дави по написанному правой кнопкой мыши и в появившейся менюшки выбирай Comlete class at cursor (по-моему так пишется (Просто в Delphi3 етого еще нет)).

Если ты всё сделал правильно, то ты должен увидеть следующее:

[code]
Procedure TForm1.gTextOut(CNV: TCanvas);

Begin

End;

[/code]

Едем дальше. Между begin и end напиши код из листинга1.

Листинг 1.
[code]

//Даем размер шрифта на холсте

CNV.Font.Size:=6;

//Даем имя шрифта на холсте

CNV.Font.Name:='COmicSansMs';

// Даем боевую раскраску шрифта на холсте

CNV.Font.Color:=clRed;

//Выводим в произвольном месте собаку (@)

CNV.TextOut(random(300),random(300),'@');

[/code]

Думаю в более подробных объяснениях листинг1 не нуждается, скажу лишь только то, что метод TextOut в общем виде имела бы следующий вид TextOut(координата_по_Х, координата_по_Y, выводимый_символ_); (Только не забудь, что ты используешь метод объекта TCanvas, а то будет вызвана одноименная API фунция TextOut, которая так же предназначена для вывода текста, но отличается количеством и типом параметров).

Теперь дабавь еще 2 процедуры вышеуказанным способом только в первой

Между begin и end впиши gTextOut(PaintBox1.Canvas), а во второй gTextOut(PaintBox2.Canvas). На практике это должно выглядеть примерно так:
[code]

Procedure TForm1.gTextOut(CNV: TCanvas); //Это уже у тебя есть

Procedure OutD1; //Это добавь

Procedure OutD2; //Это тоже добавь

Procedure Tform1.OutD1;

Begin

gTextOut(PaintBox1.Canvas);

End;

Procedure Tform1.OutD2;

Begin

gTextOut(PaintBox2.Canvas);

End;
[/code]

Эти методы получают в качестве параметра Холст и затем процедура gTextOut выводит на этом холсте собаку (@). Так а зачем мы сделали так?

{Пункт1}Дело в том, что когда методы классов одновременно вызываются из нескольких потоков, это может привести к нежелательным последствиям. Например проблемы могут вылезти при быстром чередование обработки процесса вывода изображения на экран, когда системе требуется обрабатывать объекты других классов.

Ну а теперь приступим к тому собственно из-за чего мы здесь собрались то есть к созданию потока. Кликай File->New->Thread Object.

В появившемся диалоговом окне названия класса укажем TMyThread. Этот класс будет наследником класса потока TThread. После это возникает файл с пустым описанием этого класса.

Так а теперь вернемся к нашей возможной ошибки (Пункт1) и ты поимеешь зачем мы создавали 2 «лишние» процедуры. Чтобы не возникало подобных ошибок(читай Пункт1) в классе Thread определен метод гарантированно-безопасного выполнения таких методов. Этот метод отвечает за синхронизацию всех потоков. И в качестве параметра получает только название метода. Вот именно для этого нам и понадобилось создавать 2 процедуры. Вот описание метода по синхронизации:

[code]
Type TThreadMethod= procedure of object;

Procedure Synchronize(Method: TThreadMethod);
[/code]

Едем дальше. Но вот еще один проблем как определить из внутри потока какой метод нужно вызывать в данный момент? Для того, чтобы ответить на этот вопрос введем переменную типа Boolean с именем W. Затем при создание экземпляра потока ей присвоем значение TRUE если надо выполнять метод OUTD1, и FALSE если OUTD2 соответственно.
[code]

{Как нужно описать}

Public

W: Boolean

[/code]

Сам процесс работы потока описывается в его методе Execute. После переопределения этого метода у нас получится следующее.

[code]
procedure TMyThread.Execute;

begin

while not Terminated do

if w=true then Synchronize(Form1.OUTD1)

else Synchronize(Form1.OUTD2);

end;
[/code]

И так, что это нас тут такое. СвойствоTerminated получает значение TRUE, когда прога получает значение о завершение работы. => Мы будем работать до завершения работы программы. Затем если w=true то вызывается процедура OUTD1, в противном случае OUTD2.

Теперь в разделе implementation напиши следующее: uses unit1; (Подключаем модуль1);

Теперь перейдем к первому юниту (unit1).Подключи Uni2. Затем, cоздай обработчик событий для Button1 и напиши там листин2.

Листинг2.
[code]

var T1,T2: TMyThread; {1}

T1:= TmyThread.Create(true); {2}

T1.W:=True; {3}

T1.Priority:=tpLower; {4}

T2:=TmyThread.Create(true);

T2.W:=False;

T2.Priority:=tpLowest;

T1.Resume;

T2.Resume;

[/code]

Чего мы тут натворили? В строке {1} мы описываем две переменный, это наши будущие потоки. В строке {2} мы создаем новый поток с помощью метода Create у которого есть один параметр, он имеет значение True если поток стартует после вызова метода Resume, и False если поток стартует сразу же после создания. В строке {3} устанавливаем значение переменной W ( ты же помнишь эту загогулину).В строке {4} ставим приоритет для данного потока.

Возможные варианты значений для этого свойства перечислены в таблице.
[code]
Значение Приоритет потока
tpTimeCritical Максимальный приоритет
tpHighest Приоритет на 2 пункта выше нормы
tpHigher Приоритет на 1 пункт выше нормы
tpNormal Нормальный приоритет
tpLower Приоритет на 1 пункт ниже нормы
tpLowest Приоритет на 2 пункта ниже нормы
tpIdle Поток выполняется, когда твоей ОС нечего делать[/code]

P.S. Ну вроде всё. Пример хоть и простенький, но всё же познавательный. Пожалуй, дам еще небольшой совет. У тебя есть мой код небольшой проги, но ты попробую в нем чего-то изменить, может убрать что-нибудь или прибавить своего и посмотри потом, что у тебя получится, это будет намного полезней если ты прочтешь и скажешь себе усё ПОНЯТНО! и забудешь про это. Вообще выбор за тобой. Мне остаётся лишь сказать Уд@Чи в кодинге, в девушках (глупо выразился ну смысл ты понял), и большой Уд@Чи на Сессии (если ты студент, как я). 8-)
Нравится
Не нравится
Репутация: 0
Рейтинг: 1
Кол-во тем: 0
Сообщения: 0
Довольно интересный материал. Думаю полезен не только новичкам.
Стили и нормы программирования
Необходимо использовать стиль программирования, который делает код читабельным и понятным. Несмотря на то, что некоторые разработчики имеют свой собственный стиль программирования или используют стиль программирования, принятый в их компании, хорошим тоном считается следовать стилю программирования Кернигана и Ритчи (Kernighan и Ritchie), используемому подавляющим большинством программистов на C. Однако, чересчур увлекшись, легко прийти к чему-нибудь такому: [code]
int i;main(){for(;i["]<i;++i){--i;}"];read('-'-'-',i+++«hell\
o, world!\n»,'/'/'/'));}read(j,i,p){write(j/p+p,i---j,i/i); [/code]
Dishonorable mention, Чемпионат по самому непонятному коду на C (Obfuscated C Code Contest), 1984 г. Автор кода неизвестен.
Всегда в коде можно увидеть главную функцию, называемую main(). По стандарту ANSI эта функция определяется как int main(void) (если не нужно обрабатывать аргументы командной строки) или как int main( int argc, char **argv ). Не-ANSI компиляторы могут пропускать объявление void или составлять список имен переменных и следовать их объявлениям.
Отступы
Необходимо использовать вертикальные и горизонтальные отступы. Количество и расположение отступов и пробелов должно отражать структуру кода. Длинная строка условного оператора должна быть разбита на несколько строк. Например: [code]
if (foo->next==NULL && number < limit && limit <=SIZE
&& node_active(this_input)) {… [/code]
будет лучше выглядеть как: [code]
if (foo->next == NULL
&& number < limit && limit <= SIZE
&& node_active(this_input))
{
… [/code]
Точно так же сложные циклы for должные быть разделены на несколько строк: [code]
for (curr = *varp, trail = varp;
curr != NULL;
trail = &(curr->next), curr = curr->next )
{
… [/code]
Другие сложные выражения, такие как использующие оператор ?: тоже лучше разделить на несколько строк: [code]
z = (x == y)
? n + f(x)
: f(y) — n; [/code]
Комментарии
Комментарии должны описывать то, что происходит, каким образом это происходит, что означает тот или иной параметр, какие глобальные переменные используются, а также любые ограничения и возможные ошибки. Однако необходимо избегать необязательных комментариев. Если код понятен и используются хорошие имена переменных, то, возможно, не потребуется дополнительных пояснений. Так как комментарии не проверяются компилятором, то не гарантируется, что они правильные. Комментарии, которые не согласуются с кодом, вредны. Слишком большое число комментариев приводит к беспорядку в коде. Такой стиль [code]комментирования является избыточным:
i=i+1; /* добавляем 1 к i */ [/code]
Хорошо видно, что переменная i увеличивается на единицу. И еще более плохой вариант показать это так: [code]
/************************************
* *
* добавляем 1 к i *
* *
************************************/

i=i+1; [/code]
Правила наименования
Имена с ведущими или завершающими знаками подчеркивания предназначены только для системы целей и не должны использоваться для каких-либо пользовательских имен переменных. Правила определяют следующие требования:
Константы #define должны записываться ЗАГЛАВНЫМИ символами.
Константы enum должны начинаться с заглавного символа или записываться полностью ЗАГЛАВНЫМИ символами.
Слова function, typedef и имена переменных, так же как и struct, union и enum должны быть в нижнем регистре.
Для понятности необходимо избегать имен, различающихся только регистром, например, foo и Foo. Точно так же лучше избегать одновременного использования имен foobar и foo_bar. Необходимо избегать любых имен, которые похожи друг на друга. На многих клавиатурах и во многих шрифтах l, 1 и I выглядят очень похоже. Переменная с именем l, в частности, плоха потому, что похожа на константу 1.
Имена переменных
При выборе имени переменной не так важна длина имени, как понятность. Длинные имена могут назначаться глобальным переменным, которые редко используются, но индексы массивов, появляющиеся в каждой строке цикла, не должны быть значительно сложнее, чем i. Использование index или elementnumber не только усложняет набор, но и может сделать менее понятными детали вычислений. С длинными именами иногда сложнее понять, что именно происходит в коде. Легко сравнить: [code]
for(i=0 to 100)
array=0 [/code]
и [code]
for(elementnumber=0 to 100)
array[elementnumber]=0; [/code]
Имена функций
Имена должны отражать то, что делают функции и что они возвращают. Функции используются в выражениях, часто в условных операторах if, поэтому они должны читаться соответственно. Например: [code]
if (checksize(x)) [/code]
непонятно, так как не говорит о том, возвращает ли функция TRUE при прохождении проверки или наоборот; использование вместо этого: [code]
if (validsize(x)) [/code]
делает все понятным.
Объявление переменных
Все объявления внешних переменных должны предваряться ключевым словом extern. Обозначение указателя, *, должно сопровождать имя переменной, а не ее тип: [code]
char *s, *t, *u; [/code]
вместо [code]
char* s, t, u; [/code]
Второй пример объявления переменных не является неправильным, но могут возникнуть сомнения из-за того, что t и u не объявлены как указатели.
Заголовочные файлы
Заголовочные файлы должны быть функционально организованы, т. е. объявления для различных подсистем должны содержаться в различных заголовочных файлах. Также объявления, которые являются платформозависимыми, должны быть вынесены в отдельный заголовочный файл. Следует избегать имен заголовочных файлов, совпадающих с именами стандартных библиотек. Строка #include «math.h'' включает заголовочный файл стандартной библиотеки math, если файл с таким именем не будет найден в текущем каталоге. Если такое поведение — именно то, что нужно, то лучше оставить соответствующий комментарий. Наконец, использование абсолютных путей для заголовочных файлов — не самая лучшая идея. Опция компилятора C include-path (-I на большинстве систем) — это предпочтительный метод обработки внешних библиотек и заголовочных файлов; он позволяет изменить структуру каталогов без необходимости изменения исходных кодов.
scanf
Не следует использовать scanf в серьезных приложениях. Обработка ошибок в этой функции неадекватна. Рассмотрим такой пример: [code]
#include <stdio.h>

int main(void)
{
int i;
float f;

printf(»Enter an integer and a float: ");
scanf("%d %f", &i;, &f;);

printf(«I read %d and %f\n», i, f);
return 0;
} [/code]
Запустим тест:Enter an integer and a float: 182 52.38 I read 182 and 52.380001 Теперь другой тест:Enter an integer and a float: 6713247896 4.4 I read -1876686696 and 4.400000
++ и —
При применении операций инкремента или декремента к переменной эта переменная не должна появляться в выражении более одного раза, так как итог в этом случае зависит от компилятора. Не следует писать код, который полагается на порядок обработки или особенности компилятора:
[code] int i = 0, a[5];

a = i++; /* присваивание значения a[0]? или a[1]? */ [/code]
Нельзя позволять себе видеть то, чего на самом деле нет
Рассмотрим следующий пример: [code]
while (c == '\t' // c = ' ' // c == '\n')
c = getc(f); [/code]
На первый взгляд такой оператор while выглядит корректным кодом на C. Однако использование оператора присваивания вместо оператора сравнения приводит к появлению синтаксически некорректного кода. Так как приоритет оператора = является наименьшим, то данное выражение будет интерпретировано следующим образом (скобки добавлены для наглядности): [code]
while ((c == '\t' // c) = (' ' // c == '\n'))
c = getc(f); [/code]
Левая часть оператора присваивания: [code]
(c == '\t' // c) [/code]
не приводит к появлению корректного значения. Если переменная c содержит символ табуляции, то результат TRUE и дальнейшие вычисления не выполняются, а TRUE не может быть левой частью оператора присваивания.
Явно выраженные намерения
При написании кода, который может быть интерпретирован как что-то другое, необходимо заключать этот код в скобки, чтобы быть уверенным, что намерения выражены явно. Это поможет понять намерения разработчика при последующих обращениях к коду, а также помогает в сопровождении кода. Иногда можно разрабатывать код, который предупреждает возможные ошибки. Например, можно ставить константы в левую часть оператора сравнения, т. е. вместо:
[code] while (c == '\t' // c == ' ' // c == '\n')
c = getc(f); [/code]
можно написать так: [code]
while ('\t' == c // ' ' == c // '\n' == c)
c = getc(f); [/code]
В этом случае компилятор выдаст предупреждение: [code]
while ('\t' = c // ' ' == c // '\n' == c)
c = getc(f); [/code]
Такой стиль программирования позволяет компилятору находить потенциальные проблемы; пример кода выше неправилен, так как пытается присвоить значение для \t.
Ошибки из-за специфики реализации языка программирования
Реализации языка C могут отличаться в некоторых аспектах. Необходимо иметь представление о той части языка, которая совпадает во всех реализациях. Зная это, значительно проще портировать программу на другую систему или другой компилятор, что уменьшает шансы столкнуться со спецификой компилятора. Для примера рассмотрим следующую строку:
/*/*/2*/**/1
Выражение будет интерпретироваться по правилу максимального оператора. Если комментарии могут быть вложенными, то интерпретация будет следующей:
/* /* /2 */ * */ 1
Паре символов /* соответствует пара символов */, поэтому выражение равно 1. Если комментарии не вкладываются, то на некоторых системах /* в комментариях будет проигнорировано. На некоторых компиляторах будет также выдано предупреждение для вложенной последовательности /*. В любом случае выражение будет интерпретировано следующим образом:
/* / */ 2 * /* */ 1
2 * 1 равно 2.
Сбрасывание буфера на диск
Когда приложение завершается некорректно, окончание его вывода обычно теряется. Приложение может не успеть полностью завершить вывод. Часть информации может оставаться в памяти и уже не будет записана в вывод. В некоторых системах такой незавершенный вывод может достигать нескольких страниц памяти. Потеря вывода может также привести к мысли, что программа завершилась ошибочно гораздо раньше, чем это произошло на самом деле. Способ решения такой проблемы состоит в организации принудительного вывода, особенно при отладке. Конкретная реализация этого отличается для различных систем, но обычно выглядит так: [code]
setbuf(stdout, (char *) 0); [/code]
Это выражение должно быть выполнено перед записью в stdout. В идеале этот код должен помещаться в начале функции main.
getchar() — макрос или функция?
Следующая программа выводит свои входные данные: [code]
#include <stdio.h>

int main(void)
{
register int a;

while ((a = getchar()) != EOF)
putchar(a);
} [/code]
Если удалить включение заголовочного файла #include, то это вызовет ошибку компиляции, так как значение EOF не объявлено. Программу можно переписать следующим образом: [code]
#define EOF -1

int main(void)
{
register int a;

while ((a = getchar()) != EOF)
putchar(a);
} [/code]
Это будет работать на большинстве систем, но на некоторых может быть значительно медленнее. Так как вызов функции обычно занимает довольно много времени, getchar часто реализуют в виде макроса. Этот макрос определен в stdio.h, поэтому когда #include <stdio.h> удаляется, компилятор не знает, что такое getchar. На некоторых системах полагается, что getchar — это функция, возвращающая int. В действительности многие реализации компиляторов языка C имеют свои стандартные функции getchar, частично в целях защиты от таких оплошностей. Таким образом, ситуация, когда включение #include <stdio.h> пропущено, влечет использование компилятором собственной версии функции getchar. Дополнительные вызовы этой функции делают программу медленнее. То же самое верно и для putchar.
Пустой указатель
Пустой указатель не указывает ни на какой объект. Неправильно использовать пустой указатель для любых целей, кроме присваивания и сравнения. Никогда не следует переопределять значение NULL, которое всегда должно равняться нулю. Пустой указатель любого типа должен всегда сравниваться с константным нулем, поскольку явное сравнение с переменной, имеющей значение нуль, или любой ненулевой константой будет платформозависимым. Переход по пустому указателю может вызвать странные эффекты.
Что означает a+++++b?
Единственный правильный способ интерпретации этого выражения такой:
a ++ + ++ b
Однако правило длинного оператора предписывает разбить выражение следующим образом:
a ++ ++ + b
Это синтаксически неверно, такой код эквивалентен строке:
((a++)++) + b
Но результат a++ не является lvalue и, следовательно, не может быть операндом для ++. Таким образом, правила для разрешения логических двусмысленностей не могут в этом примере привести к синтаксически верной конструкции. На практике, конечно, лучший способ избежать таких конструкций — это полная уверенность в том, что код интерпретируется однозначно. Конечно, добавление пробелов помогает компилятору понять цель оператора, но предпочтительнее (в перспективе сопровождения кода) разбить конструкцию на две строки:
++b;
(a++) + b;
Осторожное обращение с функциями
Функции обеспечивают наиболее общее структурирование кода на C. Они должны использоваться для решения проблемы «сверху вниз» — для разбиения задачи на ряд более мелких подзадач до тех пор, пока подзадача не будет легко решаться. Это помогает реализовать модульность и упростить документирование программы. Кроме того, программы, составленные из большого числа маленьких функций, значительно легче для отладки. Необходимо приводить все аргументы функций к нужному типу, если это не было сделано раньше, даже если точно известно, что компилятор осуществляет необходимое приведение типов. Делая приведение типа вручную, программист явно обозначает свои намерения и получит правильный результат при портировании приложения на другую платформу. Если заголовочные файлы не объявляют тип возвращаемого значения библиотечных функций, необходимо сделать это самостоятельно. Окружив объявления конструкцией #ifdef/#, можно упростить портирование своего кода на другую платформу. Прототипы функций используются для того, чтобы сделать код более устойчивым, а приложение — быстрым.
«Висячий» else
Нужно опасаться проблемы «висячего» else, если нет полной уверенности в правильности конструкции: [code]
if (a == 1)
if (b == 2)
printf("***\n");
else
printf("###\n"); [/code]
Правило гласит, что else принадлежит ближайшему if. В случае, если возникают сомнения или потенциальная двусмысленность, то лучше добавить фигурные скобки для обозначения структуры кода.
Границы массива
Необходимо проверять границы всех массивов, включая строки, так как сегодняшнее fubar' может стать завтра floccinaucinihilipilification. В надежном программном обеспечении не используется gets(). Тот факт, что в C элементы нумеруются с нуля, делает более вероятными ошибки подсчета. Однако требуются некоторые усилия на изучение того, как уберечься от них.
Пустой оператор
Пустой оператор цикла for или while должен размещаться на отдельной строке и комментироваться так, чтобы было понятно, что в этом месте действительно пустой оператор, а не пропущенный код:
[code] while (*dest++ = *src++)
; /* VOID */ [/code]
Проверка выражений на истинность
Не нужно оставлять по умолчанию проверку на ненулевое значение, т. е.: [code]
if (f() != FAIL) [/code]
лучше, чем
 if (f()) 

даже если FAIL имеет значение 0, которое C рассматривает как ложь (конечно, здесь нужно соблюдать баланс с такими конструкциями как, например, показанная в разделе «Имена функций»). Явное значение поможет избежать ошибок, если вдруг кто-то решит, что при неудачном завершении должно возвращаться значение -1 вместо 0. Частые затруднения вызывает функция проверки равенства строк strcmp, так как нет единого значения, означающего, что строки неравны. Предпочтительный вариант — определение в этом случае макроса STREQ: [code]
#define STREQ(str1, str2) (strcmp((str1), (str2)) == 0) [/code]
Использовать этот макрос можно в операторах следующего вида:
 If ( STREQ( inputstring, somestring ) )… 

Таким образом, функция получает желаемое поведение (не требуется переписывать или переопределять стандартные библиотечные функции типа strcmp()). Не следует сравнивать логические выражения с 1 (TRUE, YES и другими); вместо этого нужно проверять на равенство 0 (FALSE, NO и так далее). Большинство функций гарантируют возвращение 0 в случае неудачного завершения, и возвращение лишь ненулевого значения в случае удачного завершения. Таким образом, [code]
if (func() == TRUE) {… [/code]
лучше переписать так: [code]
if (func() != FALSE) [/code]
Вложенные операторы
А сейчас — время для разговора о вложенном операторе присваивания. В некоторых конструкциях нет лучшего способа присваивания, хотя он и влечет увеличение кода в операторе и ухудшение читабельности: [code]
while ((c = getchar()) != EOF) {
process the character
} [/code]
Использование вложенного оператора присваивания для улучшения производительности возможно. Однако необходимо искать компромисс между увеличением скорости и усложнением сопровождения кода, которое возникает при использовании вложенных присваиваний в неподходящем месте. Например: [code]
x = y + z;
d = x + r; [/code]
не должно заменяться на: [code]
d = (x = y + z) + r; [/code]
даже если последний вариант сможет сберечь один цикл. В долговременной перспективе разница во времени между двумя этими вариантами будет уменьшаться из-за использования компьютерной оптимизации, в то время как разница во времени, необходимом для сопровождения кода, будет увеличиваться.
Оператор goto
goto необходимо использовать крайне умеренно. Один из случаев, когда этот оператор полезен — это необходимость прервать многоуровневый оператор switch, for или while, хотя такая необходимость может свидетельствовать о том, что внутреннюю конструкцию лучше вынести в отдельный цикл. [code]
for (...) {
while (...) {

if (wrong)
goto error;
}
}

error:
print a message [/code]
Когда необходимо применять оператор goto, соответствующая метка перехода должна быть одна в строке и либо сдвинута на одну позицию табуляции влево от остального кода, либо располагаться в начале строки. В любом случае оператор goto и метка перехода должны иметь хороший комментарий по функциональности и цели использования.
«Проваливание» через switch
Когда блок кода имеет несколько меток, каждую из них нужно размещать на отдельной строке. Этот элемент стиля программирования согласуется с правилом установки вертикальных отступов и делает перекомпоновку (если она понадобится) сравнений case простой задачей. Использование предоставляемой языком С возможности «проваливания» в операторе switch должно обязательно комментироваться в целях упрощения последующего сопровождения кода. Каждый, кто испытал на себе неприятности от ошибок при использовании этой возможности, знает, насколько это важно! [code]
switch (expr) {
case ABC:
case DEF:
statement;
break;
case UVW:
statement; /*FALLTHROUGH*/
case XYZ:
statement;
break;
} [/code]
Хотя последний оператор break и не является необходимым, его использование предотвращает ошибку в случае, когда потребуется добавить еще один case. В случае, если используется вариант default, он должен быть последним и не требует оператора break.
Константы
Символические константы делают код более простым для чтения. Числовых констант, как правило, следует избегать; лучше использовать #define для задания понятного имени. Сосредоточение всех определений в одном месте (лучше всего — в заголовочном файле) также упрощает администрирование изменений в больших проектах, так как позволяет вносить изменения только в директивах #define. Можно рассматривать использование типа данных «перечисление» в качестве улучшенного способа объявления переменных, которые могут принимать только дискретные значения. Использование перечислений также позволяет компилятору выводить предупреждения при ошибках использования типа перечисления. И, наконец, явно перечисленные цифровые константы требуют меньше объяснений о своем происхождении при комментировании. Константы необходимо объявлять соответственно их использованию, т. е. необходимо указывать 540.0 для числа с плавающей точкой вместо 540 с прямым объявлением типа float. Есть случаи, в которых константы 0 и 1 могут возникать явно вместо своих объявлений строковыми константами. Например, если цикл for индексирует массив, то код: [code]
for (i = 0; i < arraysub; i++) [/code]
оправдан, а код: [code]
gate_t *front_gate = opens(gate, 7);
if (front_gate == 0)
error(«can't open %s\n», gate); [/code]
— нет. Во втором примере front_gate — это указатель; когда значение является указателем, то оно должно сравниваться с NULL, а не с 0. Даже простые значения типа 1 или 0 часто лучше воспринимаются в качестве TRUE и FALSE (или YES и NO). Не нужно использовать переменные с плавающей точкой там, где нужны дискретные значения. Это связано с не совсем корректным представлением чисел с плавающей точкой (можно вспомнить второй пример из раздела scanf выше). Сравнивать числа с плавающей точкой лучше используя <= или >=; явное сравнение (== или !=) может не обнаружить «достаточного» равенства. Символьные константы должны быть объявлены как символы, а не как числа. Нетекстовые символы являются более трудными для портирования. Если нетекстовые символы необходимы, в частности, при использовании в строках, они должны быть записаны в виде управляющих последовательностей из трех восьмеричных цифр, а не одной (например, '\007'). Даже в этом случае такое использование символов является платформозависимым и должно восприниматься таковым.
Условная компиляция
Условная компиляция полезна в случаях, когда требуется реализовать машинозависимый код, при отладке и для установок значений во время компиляции. Различные варианты управления могут легко привести к непредвиденным ситуациям. При использовании #ifdef для машинозависимого кода необходимо быть уверенным, что если тип машины не определен, то возвращается сообщение об ошибке, а не используется конфигурация по умолчанию. Директива #error предназначена как раз для этих целей. При использовании #ifdef для оптимизации лучше применять по умолчанию неоптимизированный код, чем некомпилируемый или некорректный. Необходимо тестировать неоптимизированный код.
Разное
Утилиты для компиляции, такие как make, значительно упрощают задачу переноса приложения из одного окружения в другое. В процессе разработки make перекомпилирует только те модули, которые были изменены со времени последней компиляции. Необходимо использовать lint как можно чаще. lint — это тестер C-программ, который проверяет исходные файлы на языке C для обнаружения несовместимостей типов, расхождений между объявлениями функций и их вызовами, потенциальных ошибок в программе и тому подобного. Также необходимо изучить документацию компилятора и выяснить, какие опции сделают его более «разборчивым». Работа компилятора заключается в том, чтобы быть точным, поэтому необходимо дать ему возможность выдать отчет о потенциальных проблемах, используя соответствующие опции компиляции.
Необходимо стараться минимизировать количество глобальных переменных. Один из выигрышей от этого заключается в уменьшении вероятности конфликтов с системными функциями.
Многие программы завершаются некорректно, когда не получают ожидаемых входных данных. Все программы должны тестироваться на пустые входные данные. Это также поможет понять, как работает программа.
Не следует полагать о пользователе или его поведении больше, чем этого требует программа. То, что «никогда не может произойти», иногда происходит. Надежная программа защищена от подобных случаев. Если есть непроверяемое граничное условие, то пользователь обязательно столкнется с ним! Никогда не нужно делать предположений о размере заданного типа данных, особенно указателей. При использовании в выражениях переменных типа char в большинстве реализаций компиляторов полагается этот тип данных как беззнаковое целое, но в некоторых — как знаковое. Поэтому разумнее каждый раз приводить этот тип данных к требуемому при использовании в арифметических выражениях. Не нужно полагаться на автоматическую инициализацию переменных и памяти, возвращаемой функцией malloc.
Следует делать понятной структуру программы и ее цели.
Необходимо всегда помнить, что разработчику в будущем может потребоваться модифицировать код или перенести его на другую платформу. Поэтому лучше сразу создавать код, который может быть легко портирован.

Заключение
Общеизвестно, что сопровождение приложения отнимает значительную часть времени программиста. Частично это происходит из-за использования платформозависимых и нестандартных особенностей, но в большей степени — из-за плохого стиля программирования. В этой статье дается несколько советов, которые помогают сберечь время, требуемое для сопровождения кода. Следование этим советам сделает сопровождение приложений командой разработчиков более простым.
Нравится
Не нравится
Репутация: 0
Рейтинг: 1
Кол-во тем: 0
Сообщения: 0
[B]Уязвимости в исходных кодах[/B]
Автор: StraNger

[intro]
Еще не просматривали bugtrack? Я уже заглянул сегодня. Опять куча уязвимостей. Опять куча эксплоитов. Программисты тоже люди, а потому могут допускать ошибки. И эти ошибки стоят root-a. JИтак, сегодня мы поговорим о такой вещи, как «баги» исходного кода. Как вы знаете, ошибки допускаются и в скриптах, и в прикладных программах. В этой статье я хотел бы рассказать об ошибках в программах на языке Си. От вас понадобится знание языка, основ переполнения буфера и построения эксплоитов.

[GO!]

Вообще, цель использования уязвимости в программе это передать целевой системе shellcode, который выполнит необходимые действия. Но некоторые уязвимости можно реализовать, не прибегая к шеллкоду. Например, вызвать «отказ от обслуживания» (DoS).
Давайте разложим все это по полочкам: при поиске уязвимостей бывают частные и нечастные случаи. К частным можно отнести известные «баги» вроде ошибки форматной строки или переполнения буфера (Buffer Overflow). К нечастным случаям можно отнести то, что мы находим при определённых обстоятельствах. Эти уязвимости нигде не описаны, т.е. приходится рассчитывать только на свои мозги.

Если копать глубже, то бывают ошибки, которые можно использовать локально, а бывают, которые мы реализуем удаленно. Естественно, это зависит от приложения, в котором была найдена уязвимость. Ошибки в разных сетевых службах, как вы, наверное, догадались, мы реализуем удаленно. Часто такие ошибки эксплуатируем для DoS. Но бывает, что можно поднять свои права.

А если у нас есть доступ к серверу и вы нашли там программу с SUID битом, в которой присутствует уязвимость, то можно запустить shell с правами рута. Ошибка может находиться в самом ядре системы, что тоже может повысить наши привилегии.

К примеру, недавно была обнаружена дыра в Linux kernel 2.6.30, она позволяет выполнять произвольный код с правами root. Уязвимость появилась из-за ошибки разыменования нулевого указателя.

Как видите, ошибка не тривиальная. И для грамотного поиска нужно очень хорошо знать язык Си и особенности системы. Давайте поговорим о том, на что нужно
обращать внимание при поиске уязвимых мест.

[Поиск жучков.]

При аудите исходного кода (в жаргоне «сорца»), в первую очередь нужно обязательно смотреть на данные, которые поступают из внешних источников (часто от пользователя). Т.е. большинство переполнений бывает как раз из-за неграмотной проверки входящих данных. Вообще специалисту по безопасности кода можно жить только с одним правилом: «Проверяй все входящие данные».

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

При вычислениях нужно обращать внимание, не выходит ли значение за пределы диапазона типа переменной. Если непонятно, приведу пример: переменная типа «integer». Ее диапазон 2147483648 до 2147483648, а если значение будет больше, то поведение программы может выйти из-под контроля. Например, в gcc такая ошибка приводит к тому, что программа выполняет обратное действие. Если вы прибавляли 10, то будет делать наоборот, т.е. отнимать. Это называется Integer Overflow.

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

Кроме всего прочего нужно заострять внимание на таких опасных функциях, как
strcpy() ,getc(), strcat(), spintf(), printf(), vsprinf(), system() и т.п. Замечу одну интересную вещь: как известно, потенциально опасная функция strcpy() может быть заменена якобы безопасной функцией strncpy(). Но безопасной эта функция будет только при правильном использовании.

Вот пример: stridency(a,b,sizeof(b)); Вроде все правильно, и кусок кода безопасный. Но если сделать так (как многие и делают):
[code]
strncpy(a,b,strlen(b));
[/code]
то функция становится опасной к переполнению.
Хочу еще сказать, что для аудита безопасности кода существует множество программ. Думаю, не стоит говорить, что доверять им нельзя. Но, все же, я приведу в пример несколько:

BOON (Buffer Overrun detectiON)- из названия уже ясно, что программа производит поиск ошибок переполнения буфера в коде.

FlexeLint у этой программы круг уязвимостей больше: например она предупреждает об опасном стиле кода. Тоже ищет переполнения буфера, а также арифметические переполнения и т.п.

KlocWork K7 аналогично выявляет дефекты и проблемы безопасности исходного кода.
Если вас заинтересовали эти сканеры, подробнее можете почитать [url=http://www.codenet.ru/progr/other/code-analysers.php]здесь[/url]

[Примеры реальных уязвимостей]

Ниже я приведу несколько потенциально уязвимых кусков кода, попробуйте самостоятельно найти «багу», а если не получится, то читайте мое решение.
[code]
int main(int argc, char *argv[])
{
char in[255];
int r,f;
sprintf(in,«ls»,argv[1]);
r=system(in);
if(!r)
{
f=open("/tmp/log",O_RDONLY,0);
printf(«OK!»);
}
}
[/code]
Во-первых, сразу видим, что буфер «in» статистический. Память для него выделена сразу же. Впоследствии это может привести к переполнению при работе с функцией sprintf():
Во-вторых, используется функция system(). Она, как известно, становится опасной, если ее аргументы не проверять. Тут как раз такой случай. Можно передать строку, которая скомпрометирует целевую систему на действия нежелательные для администратора.
[code]
int baga(char *arg){
char *v;
int i,f;
v=(char*)malloc(sizeof(arg))
i=strlen(v);
if(i>10)
{
f=creat("/tmp/import/",0666);
}
else-
{
printf(«Sorry. this prorgamm lol\n»);
}
}
[/code]
Уязвимость присутствует при создании временного файла «/tmp/exampl». Дело в том, что можно создать жёсткую ссылку /tmp/exampl на какой-нибудь другой файл, и произойдет конкуренция доступа к каталогу tmp.
[code]
int main(int argc, char *argv[])
{
char v[100];
if(argc>1)
{
strcpy(v,argv[1]);
}
else
{
printf(«No symbol\n»);
}
}
[/code]
Тут присутствует самое банальное переполнение буфера v []. Его размер 50, а функцией strcpy() мы можем переполнить буфер. Количество входных данных не проверяется.
[code]
int main(int argc, char *argv[])
{
if(argc>1)
{
printf(«argv[0]»);
}
else
{
printf(«No symbol\n»);
}
[/code]
В этом примере, если аргументы больше единицы, мы печатаем имя исполняемого файла Невооружённым глазом видна ошибка форматной строки. Если в названии программы будут спецификаторы для printf(), то можно произвести кое- какие действия. Например, если название будет таким: %x_%x_%x_name, можно получить содержимое стека.
[code]
int main(int argc, char *argv[])
{
add=atoi(argv[1])
real=1000000000;
printf(«Введите кол-во у.е. которые вы хотите добавить\n»);
real+=add;
}
[/code]
Тут есть место атаки класса integer overflow. О ней я уже говорил.

Переменная add не проверяется, т.е. все это может выйти за пределы диапазона integer.

А как же сетевые службы? Приведу опять же пример. Допустим, есть ftp демон. После подключения к нему запрашивается login:password. Так вот, они могут не проверяться. Их переполнение приводит к DoS.

Мы разобрали несколько опасных уязвимостей. Чтобы как то подкрепить полученные знания практикой, я покажу пример простенького сплоита. Он реализует ошибку переполнения буфера. Если вы знакомы с ней, то знаете, что shellcode можно передать через стек, через кучу и через переменную окружения. Через стек, наверное, самый распространённый способ. Я покажу реализацию передачи шелл кода через переменную окружения.

Скажу сразу, что эксплоит лишь показательный. В реальных условиях маловероятно, что его можно применить. Но для примера он подходит. Объяснять технику написания сплоитов я не буду, т.к. это тема заслуживает отдельной книги.
Итак, возьмём уже известную нам программу:

[code]
//proga
int main(int argc, char *argv[])
{
char v[100];
if(argc>1)
{
strcpy(v,argv[1]);
}
else
{
printf(«No symbol\n»);
}
}[/code]
Вот так примерно можно передать шеллкод через переменную окружения:

[code]
#include<stdio.h>
#include<string.h>
#include<unistd.h>
int main()
{
char shellcod[]=//Собсно сам код. Но его не пишу.
char *e[2]={shellcod,NULL};
char b[127];
int i,ret,*ptr;
ptr=(int*)(b);
ret=0xbfffffff-5-strlen(shellcod)-strlen("./proga");
for(i=0;i<127;i+=4)
{*ptr++=ret;
}
execle("./proga",«proga»,b,NULL,e);
}[/code]
Сначала мы подготавливаем буфер для внешней переменной, в которой будет шелл код:
[code]
char *e[2]={shellcod,NULL};[/code]
Потом буфер для переполнения:
[code]
ptr=(int*)(b);[/code]
Потом подсчитываем адрес шеллкода, по которому он будет после исполнения функции execle
ret=0xbfffffff-5-strlen(shellcod)-strlen("./proga");

Далее загружаем программу с переполняющим буфером и shell кодом во внешние переменные[code]
execle("./proga",«proga»,b,NULL,e);[/code]
Произошло переполнение.

Вот и все.

[OUTRO]

Ошибки были, есть и будут. Этого не избежать. Вопрос только во времени и в вашей осведомленности в данной области.

Эта статья рассказывает лишь о малой доле «дыр» в исходных кодах. Если хотите продолжать, то нужно практиковаться: читать код, искать лазейки. Советую чаще посещать bugtrack, в нем обычно всегда описывают причину уязвимости и часто к описанию прилагается exploit.

Вот несколько толковых багтраков:

[url]www.securitylab.ru;[/url]
[url]www.securityvulns.ru;[/url]
[url]www.packetstormsecurity.org;[/url]
[url]www.inj3ct0r.com[/url]

Надеюсь вы узнали что то новое и не потратили время зря. Удачи!

Июль 2009 года.
Нравится
Не нравится
Репутация: 0
Рейтинг: 0
Кол-во тем: 0
Сообщения: 0
1)
[PHP]$name = «Ваня»;
echo «Привет, дядя $name!!! Сегодня хорошая погода...=)»;
[/PHP]
будет работать хуже, чем:
[PHP]
$name = 'Ваня';
echo 'Привет, дядя '.$name.'!!! Сегодня хорошая погода...=)';
[/PHP]
Потому что в одинарных кавычках не будет производится поиск и замена переменных, а когда используете двойные кавычки, что интерпритатор будет там искать переменные и потеряет время…

2)[PHP]$test[a]=1;[/PHP]будет работать хуже, чем:[PHP]$text['a']['b']=2;[/PHP]

3)Регулярные выражения eregi устарели и работают медленее, чем preg_match.
str_replace быстрее, чем preg_replace, но strtr быстрее, чем str_replace.

4)[PHP]print('hello');[/PHP]будет работать хуже, чем:[PHP]echo 'hello';[/PHP]

5)Код лучше записывать в короткие строки. Это не только улучшает читабельность кода человеком, но и интерпритатором.

6)Лучше минимально нагружать сервер большими библиотеками. Иногда лучше «изобретать велосипед», чем подключать лишие 5мб
Нравится
Не нравится
Репутация: 0
Рейтинг: 1
Кол-во тем: 0
Сообщения: 504
Блин, только хотел добавить эту заметку в топик, который создал кевин, и уже потерли :lol:

Вобщем, объектное программирование средствами C:
[code]
#include <stdio.h>
#include <stdlib.h>

#define PRIVATE

/* интерфейс объекта */
typedef struct ICat
{
void (*voice)(void);
int (*get_age)(PICat);
void* obj_handle;
} ICat, *PICat;

/* сам объект = интерфейс + приватные методы/поля */
typedef struct Cat
{
ICat ani_interface;
int age;
void (*set_age)(void*, int);
} Cat, *PCat;

/* члены объекта */
void voice()
{
printf(«meow!\n»);
}

int get_age(void* this_obj)
{
int result;
Cat* this = (Cat*)this_obj;
result = ((Cat*)this_obj)->age;
return result;
}

PRIVATE void set_age(Cat* this, int new_age)
{
this->age = new_age;
}

/* конструктор объекта Cat */
ICat* cat_construct(int age)
{
/* создаем объект и интерфейс для него */
Cat* this = (Cat*)malloc(sizeof(Cat));
ICat* instance_iface = (ICat*)malloc(sizeof(ICat));

/* инициализируем интерфейс */
instance_iface->get_age = get_age;
instance_iface->voice = voice;
instance_iface->obj_handle = (void*)this;

/* инициализируем объект */
this->set_age = set_age;

/* далее та часть, которую пишут в конструкторе на языках типа c++ */
/////////////////////////////////////////////////////////////////////
this->age = 1;

/////////////////////////////////////////////////////////////////////


/* возвращаем интерфейс созданного объекта */
return instance_iface;
}

[/code]Этот пример — реализация самого простого объекта типа Cat, по аналогии с классом c++:

[code]
class Cat
{
public:
Cat(int age);
int get_age();
void voice();
private:
int age;
void set_age(int);
};
[/code]Здесь еще нет всякого наследования и полиморфизма, а также RTTI и vtable. Но думаю этого простого примера достаточно, чтобы понять, сколько лишних сущностей плодит ООП :)
Нравится
Не нравится
Репутация: 0
Рейтинг: 0
Кол-во тем: 0
Сообщения: 0
Всем привет вот решил тоже добавить свой труд в HackZona меня очень заинтересовало кавычки в php, чем же они отличаються и как оптимизировать код с помощью использование кавычек

Раньше уже использовалось про кавычик, phpdreamer'ом, но он только у поминул часть. Прошу сразу извенить меня если неправильно написаные предложения очень старался и строго не критикуйте.

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

Кавычки, что логично, бывают одинарными и двойными. Различие их использования в php заключается в следующем. Строку, заключенную в одинарные кавычки, интерпретатор php выводит как есть, заключенную же в двойные кавычки парсит на наличие в ней переменных и, найдя таковые, подставляет их значения.

[code]
<?php
$var = 1;
echo '$var'; //на экран выведется "$var"
echo "$var"; /*на экран выведется цифра 1, т.к. вместо переменной подставляется ее значение*/
?>
[/code]

Следовательно, если нам надо вывести текст «как есть», то используем одинарные кавычки. Если необходимо подставить вместо переменной ее значение двойные (если переменная только одна, то кавычки можно и вовсе опустить). Часто можно встретить такой код:

[code]
<?php
echo «Какой-то текст»;
?>
[/code]

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

Рассмотрим тривиальную задачу вывода переменной в составе текста, в том числе и с использованием html кода.

[code]
<?php
$date;
echo «Сегодняшняя дата: $date»;
?>
[/code]

Все выводится хорошо, текст и выделенная жирным дата, которая подставляется вместо переменной. Но необходимо помнить две вещи. Первое, это особенность интерпретатора: конкатенация строк происходим намного быстрее и требует меньше ресурсов, нежели синтаксический анализ строк. И второе — не стоит забывать про парадигму программирования «разделяй и властвуй». Не надо мешать все в одно, гораздо правильнее будет разделить текст на две части требующую и не требующую парсинга интерпретатором. Таким образом, пример выше стоит записать так:

[code]
<?php
$date;
echo 'Сегодняшняя дата: '.$date.'';
?>
[/code]

Естественно, следование этому правилу (заключать все, что не требует парсинга, в одинарные кавычки) надо не только при выводе текста, но и при присвоении значений строковым переменным:

[code]
<?php
$svar = 'Значение переменной';
?>
[/code]

Или, например, при использовании строк при передаче аргументов функции:

[code]
<?php
function sum_str($first_string, $second_string) {
return $first_string.' — '.$second_string;
}
$var = 'Параметр';
echo sum_str($var, 'значение'); /*на экран выведется строчка «Параметр — значение»*/
?>
[/code]

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

Вот и подошла статья к концу. Думаю это статья поможет не только новичкам но и опытным программистам.

P.S. Спасибо что прочитали до конца мне очень интересно ваше мне о этой статьи пишите мне в ПМ с критикой.
Нравится
Не нравится
Репутация: 0
Рейтинг: 0
Кол-во тем: 99
Сообщения: 0
Привет всем, хочу написать небольшую заметку. Итак, допустим у нас есть такой код:

[CODE]int main()
{
char *Number(void);
printf("%s", Number());
}

char *Number(void)
{
int i;
char text[10];

for(i=0;i==9;i++)
text=(char)i;
return &text;[0];
}[/CODE]

Вы видите в нем ошибки? А я вижу. В последней строке «return &text;[0];». Функция возвращает адрес локальной переменной(указатель), хотя после передачи адреса переменная будет уничтожена, и мы получим «висячий указатель», и такие ошибки допускаются программистами довольно часто. Кстати говоря компилятор предупреждает нас:

[QUOTE]script.c: В функции Number:
script.c:16: предупреждение: функция возвращает адрес локальной переменной[/QUOTE]

Предупреждать предупреждает, но не говорит, что в этом плохого, потому многие закрывают глаза на подобные предупреждения. Подробнее о «висячих указателях» и то к чему они могут привести, можно прочитать в моей статье "[URL=«kerny-auroras.blogspot.com/2009/11/blog-post.html»]Ссылка в никуда или сломанный указатель[/URL]".
Нравится
Не нравится
Репутация: 0
Рейтинг: 1
Кол-во тем: 0
Сообщения: 504
Некоторые программисты допускают ошибочное суждение о том, что HTTP_X_FORWARDED_FOR содержит реальный адрес клиента, и активно используют это значение в своих скриптах. Казалось бы, получив этот заголовок, можно сделать как минимум два вывода:
1. используется http-прокси
2. прокси прозрачный и он сообщил нам IP-адрес или цепочку IP-адресов до конечного пользователя (включая и его адрес)

Типичный шаблон кода, определяющего реальный удаленный IP, выглядит примерно так:
[code]
$real_addr = "";
if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
$real_addr = $_SERVER['HTTP_X_FORWARDED_FOR'];
else
$real_addr = $_SERVER['REMOTE_ADDR'];
[/code]

В действительности же, заголовок HTTP_X_FORWARDED_FOR является абсолютно ненадежным источником реального IP, а его наличие не может даже ответить на вопрос «используется ли прокси».

Вот пример.

Запрос отправляется напрямую клиентом, без использования http-прокси
[code]
GET / HTTP/1.0

HTTP_X_FORWARDED_FOR: 74.125.232.50
[/code]
в результате такого запроса скрипт будет думать, что именно этот адрес и является реальным IP удаленного пользователя. Кстати, вышеуказанный IP является одним из списка результатов прямого запроса DNS A-записи google.ru
Весьма интересный эффект может получится в редких случаях, когда скрипт по-особенному ведет себя при $real_addr = «127.0.0.1».
Нравится
Не нравится
Репутация: 0
Рейтинг: 0
Кол-во тем: 0
Сообщения: 0
[QUOTE=phpdreamer;108592]

2)[PHP]$test[a]=1;[/PHP]будет работать хуже, чем:[PHP]$text['a']['b']=2;[/PHP]

[/QUOTE]

Не согласен с данным утверждением!!!

Попробуем слелать так:
ini_set('display_errors',1);
ini_set('display_startup_errors',1);
ini_set('error_reporting',E_ALL);
$test[a]=1;#Даст ошибку, сказав что a и b неизвестные константы.
Ключ массива можно НЕ заключать в скобки в том случае, если это числовая строка.
Например, $test[2][78]=1;
В случае, если имя Ключа является строкой, его необходимо заключить в скобки.

$test['a']['b']=1;#будет работать лучше.

Хотя продолжая тему, замечу, что писать стоит в одинарных кавычках(') нежели чем в двойных("):

$test[«a»][«b»]=1;#будет работать лучше.

$test['a']['b']='1';#будет работать хуже.

Вообще, если речь идёт о цифрах, не нужно их заключать в кавычки.
Например,

if($test['a']['b']==1){}#будет работать лучше.

if($test['a']['b']=='1'){}#будет работать хуже.
А вообще в данном случае лучше записать:

if($test['a']['b']){}#будет работать ещё лучше.

По сути это больше для параноиков, таких например, как я)))) которые учитывают каждый байт во время кодинга.
Нравится
Не нравится
Репутация: 0
Рейтинг: 0
Кол-во тем: 56
Сообщения: 120
1. Взлом сайтов и web-проектов любой сложности и тематики:
— Форумы
— Бизнес сайты
— Сайты-визитки
— Корпоративные сайты и любые другие.
2. Взлом почты, взлом корпоративной почты, взлом зарубежной почты:
— yahoo.com, live.com, mail.com, aol.com, hotmail.com, и пр.
— mail.ru, yandex.ru, bk.ru, rambler.ru и пр.
— любая корпоративная или экзотическая почта будет вскрыта.
3. Получение удаленного доступа к ПК:
— Mac, Win, Unix и пр.
— получу удаленный доступ к любому ПК, выкачаю файлы, удалю файлы, заблокирую доступ и любые, даже экстравагантные, просьбы.
Контактный адрес — [email protected]

4. Удалю всё, что мешает в интернете, очищу любые ресурсы: блоги, форумы, каналы YouTube, новостные ресурсы и даже БАЗЫ ДАННЫХ любых учреждений:
— очистим любую информацию, что есть в сети, готовы почистить поисковые системы, чтобы не выдавали информацию по нужному запросу — сделаем в лучшем виде.
5. Взлом Iphone и любых приложений:
— взлом viber, whatsapp, и любых других приложений
— получение удаленного доступа к телефону и выкачка/удаление любой информации. Установка слежки за жертвой.
6. Любые операции с Мобильными Операторами:
— распечатка сообщений, прослушка звонков
— определение местонахождения абонента в реальном времени
— установка защиты от перехвата смс и от прослушки.
По всем вопросам писать на [email protected]

7. Взлом социальных сетей, работаем с зарубежными сетями:
— взлом vk
— взлом facebook
— взлом ok
— взлом мамба
— взлом loveplanet.
И любых других социальных сетей, повторяю: работаем также с зарубежными.
8. Работаем по взлому FOREX, в финансовых направлениях, на тендерных площадках:
— взлом любых тендерных площадок, есть готовые решения
— взлом в FOREX направлениях, работаем с MT4, MT5
— взлом банковских аккаунтов и счетов
Любой другой взлом и направления — их масса — выслушаем Ваши запросы.
9. Взлом Skype и любой другой телефонии.
10. Взлом серверов ЛЮБЫХ типов.
Сделать заказ можно на [email protected]
Для того, чтобы отвечать в темах на форуме необходимо войти на сайт или зарегистрироваться.