4 заметки с тегом

си

Числа от «n» до нуля без сравнений

На «Хабре» интересную задачу увидел, требуется написать на Си программу, выводящую числа от «n» до нуля, не используя (скрыто или явно) операторы сравнения.

Мой вариант:

#include <stdlib.h>
#include <stdio.h>

void print(const int n) {
	printf("%d\n", n - 1);
}

int main(int argc, char* argv[])
{
	const int N = atoi(argv[argc - 1]);

	void (*f[])(int) = {print, exit};
	for (int n = -1;;n++) {
		f[~n/~N](N - n);
	}
}
31 октября   программирование   си

Структуры в Си и CGO

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

Для начала посмотрим как определяются и передаются структуры в Си. Полную спецификацию я приводить не буду, посмотрим на два распространённых способа. Первый используется в этом небольшом примере:

#include <stdio.h>
#include <math.h>

struct point {
	double x, y;
};

double point(struct point p) {
	return sqrt(pow(p.x, 2) + pow(p.y, 2));
}

int main() {
	printf("%g\n", point((struct point){1, 2}));
}

Тут можно обратить внимание на две особенности — во-первых, везде, где мы используем структуру, приходится использовать и ключевое слово struct, во-вторых, в коде существует и структура point, и функция с таким названием.

Это происходит потому, что имена структур обитают в своём собственном пространстве имён, на его использование и указывает struct. Там же живут имена объединений (union) и перечислений (enum). Имена функций находятся в общем пространстве, так что два таких определения с одним именем друг другу не мешают.

Структуры, объявленные таким образом видны через CGO компилятора Гоу как C.struct_name (C.struct_point в данном случае). К сожалению, тут есть особенность, о которую я споткнулся — если запрашиваемая структура не определена, то Гоу не выдаст ошибки, мы просто получим пустую структуру:

package main

import ("C"; . "fmt")

func main() {
	Println(C.struct_undefined{}) // ошибки не будет
}

Но программисты — люди ленивые, писать всюду struct неудобно. К счастью есть способ этого не делать — можно завести структуру, а потом дать ей имя в пространстве всех остальных типов. Это делается при помощи ключевого слова typedef позволяющего создавать алиасы типов:

struct point {
	double x, y;
};

typedef struct point point;

Теперь у нас есть два имени для одного типа — один в пространстве структур и прочего, второе — в общем пространстве. Можно даже сделать их одинаковыми, что очень удобно. Если второе имя нам ни к чему (бывают случаи, когда оно необходимо, но я не буду их тут рассматривать), то можно определить анонимную структуру и сразу дать имя этому типу в общем пространстве, так тоже будет работать.

Это нас подводит ко второму способу работы со структурами:

#include <stdio.h>
#include <math.h>

typedef struct {
	double x, y;
} point;

double veclen(point p) {
	return sqrt(pow(p.x, 2) + pow(p.y, 2));
}

int main() {
	printf("%g\n", veclen((point){1, 2}));
}

Ключевое слово struct перед типом уже не нужно, раз все имена в общем пространстве. Это же касается и CGO.

Как раз на эти грабли я и наступил — позабыл про эти все особенности. Когда я ещё писал на Си, всегда пользовался вторым способом, с именем в общем пространстве и привык к тому, что это и есть структуры.

Триграфы в Си

Век живи, век учись, больше заработаешь. Язык C я недолюбливаю, преимущественно из-за собственной лени, но, в своё время знал его достаточно хорошо. Но я не знал, что в C есть так называемые «триграфы»:

Вообще триграфы были придуманы для терминалов, в которых некоторых символов не хватает. В итоге вместо #define можно написать ??=define. Триграфы подменяются на нужные символы в самом начале, поэтому эти записи эквивалентны. Вместо { можно написать ??< , вместо } использовать ??>

Остальные триграфы можно найти в статье Елены Сагалаевой «Триграфы и альтернативные символы» на её персональном блоге. Кстати, очень рекомендую сам блог — отличное чтиво на темы связанные с программированием.

Мой mod_autoindex

Испокон веков в Apache (внимание! речь идёт об Apache 1.x) существует модуль mod_autoindex — в комментариях в его исходном коде есть дата, видимо написания первой версии — 23 марта 1993 года. С тех пор модуль, очевидно, претерпевал какие-то изменения, но с 1993 года форматирование вряд ли изменилось — всё тот же тег PRE.

С 1993 года HTML обогатился таблицами и каскадными стилями (CSS). Вряд ли сейчас кто-то использует браузеры не знающие что это такое, странно, что для вывода информации в модуле mod_autoindex до сих пор используется PRE. Сам по себе модуль очень неплох — он позволяет быстро (часто для этого вообще ничего не надо делать — просто убрать индексный файл из папки) организовать файловые архивы, а главное — организовать их без использования относительно медленного скриптинга, что может часто бывает критично для сервисов, пользующихся большой популярностью.

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

Стандартный модуль Apache позволяет менять, в этом плане:

  • header, т. е. часть над списком файлов (HeaderName, SuppressHTMLPreamble)
  • footer, часть под списком файлов (ReadmeName)
  • размер иконок (IconWidth, IconHeight)
  • внешний вид иконок (AddIcon, AddIconByType, AddIconByEncoding)
  • убирать из списка некоторые столбцы (SuppressLastModified, SuppressSize, SuppressDescription)
  • изменять описание файла (AddDescription)
  • и весьма ограниченно менять внешний вид выводимой информации (FoldersFirst, SuppressColumnSorting и т. п.)

Чаще всего этого для «упаковки» списка файлов в дизайн очень мало. Для облегчения задачи интеграции вывода mod_autoindex в дизайн я несколько усовершенствовал этот модуль. Всё по порядку.

Что умеет новый модуль

my_mod_autoindex (10.06КиБ)
  • Режим FancyIndex всегда включен и не выключается. Вряд ли найдётся много людей
    не использующих этот режим.
  • В основном режиме (об этом подробнее — чуть ниже) таблица файлов выводится при
    помощи тега TABLE, где у большинства объектов (например, у первой строка, чётных
    и нечётных строк) прописаны идентификаторы CSS-классов, из чего следует, что внешний
    вид таблицы вы легко сможете задать при помощи файла стилей.
  • Новая опция, позволяющая включить в листинг файла ссылку на корень сайта
    (IndexOptions +RootFolder, при использовании не забудьте добавить иконку,
    например так: «AddIcon /icons/back.gif .»)
  • Появилась возможность перенести Description в отдельную (новую) строку
    (IndexOptions +DescriptionAtNewRow)
  • Появилась возможность локализовать (перевести на родной язык) текстовую
    информацию модуля (директивы ParentStr, RootStr, NameStr, SizeStr, DescriptionStr, LastModifiedStr).
  • С первой страницы (если пользователь находится в корне сайта) убрана
    ссылка «Parent Directory», ведущая в этом случае, на ту же самую страницу.
  • Появился новый режим вывода, основанный на теге SPAN (именно он на иллюстрации),
    в частности, количество иконок в строке в этом режиме зависит от ширины окна браузера
    (IndexOptions +BoxWidth=N +BoxHeight=N +MaxIconHeight=N)

Новый режим вывода  

Прямоугольник (7.08КиБ)

Новый режим вывода включается автоматически, если были использованы параметры BoxWidth и BoxHeight. Эти два параметра отвечают за размер прямоугольника, в который заключена иконка (на иллюстрации выделено чёрным) и, по сути, определяют расстояние между соседними иконками.

Размер этот нужно выбирать исходя из размеров иконки, текста названия файла и строки, где выводится размер файла, плюс некоторое пространство, необходимое для обеспечения зазора между соседними иконками. Есть ещё один параметр — MaxIconHeight, выбрать его просто — это всего лишь максимальная высота иконки в вашем наборе. Нужен этот параметр для того, чтобы подписи к иконкам располагались на одном уровне (на иллюстации — синяя линия).

В этом режиме под иконкой выводится имя файла, размер и дата модификации (если, конечно, не были использованы опции SuppressLastModified и SuppressSize), описание файла выводится в аттрибут «title» тега SPAN, охватывающего иконку и надписи (если не была использована опция SuppressDescription) — вы можете использовать DHTML, чтобы выводить информацию из title в статусную строку, всплывающую подсказку и т. п.

Пример

Файлы для вывода информации так, как это изображено на иллюстрации выглядят так:

Файл «.htaccess»:

IndexOptions +SuppressHTMLPreamble +NameWidth=*
IndexOptions +SuppressLastModified +FoldersFirst +RootFolder +DescriptionWidth=*
IndexOptions +BoxWidth=80 +BoxHeight=80 +MaxIconHeight=33

HeaderName /_bolk_autoindex/.HEADER.html
ReadmeName /_bolk_autoindex/.FOOTER.html
ParentStr "Наверх"
RootStr "В корень"
NameStr "Имя"
SizeStr "Размер"
DescriptionStr "Описание"

Файл «.HEADER.html»:

<head>
    <title></title>
    <style type="text/css">
    td,
    body { background-color: white; font-family: Verdana,Tahoma; font-size:10px }
    a    { color: black; text-decoration:none }
    .cell0, .cell1 {text-align: center}
    a:hover { text-decoration: underline }
    </style>

</head>
<body>
<h4>Пример использования</h4>
Содержимое каталога:
<!--#echo var="DOCUMENT_URI" encoding="none" -->
<br clear="all" /><br />

Файл «.FOOTER.html»:

</body>

Где взять и как установить

Файл можно взять у меня на сайте (ZIP, около 15Кб), для установки нужно переписать его на место старого модуля (каталог src/modules/standard) и перекомпилировать Apache.   Проблемы и их решения

Часто, помимо имени файла, его размера и даты создания, хочется вывести другую полезную информацию — например, разрешение для картинок, ID3 теги для MP3 файлов и так далее. Для этой цели я рекомендую воспользоваться полем «Description» и директивой «AddDesription». Задачей модуля не является и, надеюсь, не будет являться (иначе это приведёт к снижению производительности) автоматический вывод информации такого рода. Напишите скрипт (кстати, возможно позднее я его выложу), который пробежит по каталогам и добавит эту информацию в соответствующие .htaccess файлы и вызывайте его далее по мере необходимости.

Один из заказчиков попросил предоставить пользователю возможность самому выбирать какой вид листинга файлов он хочет получить — табличный или в виде иконок. К сожалению, у Apache 1.x нет методов переключения конфигурации в зависимости от каких-то внешних условий «на лету», так что было выбрано такое решение. На портах 80 и 443 (обычно используется для HTTPS-соединений) были заведены два виртуальных хоста:

<VirtualHost example.com:80>
...
AccessFileName .htaccess .htaccess-table
...
</VirtualHost>

<VirtualHost example.com:443>
...
AccessFileName .htaccess .htaccess-icons
...
</VirtualHost>

где прописаны одно общее имя .htaccess-файла для общих настроек и деректив AddDescription и два разных имени для различных наборов настроек mod_autoindex. Переключение происходит перенаправлением пользователя на определённый порт.   Хотелось бы ещё...

По всем вопросам, с пожеланиями по улучшению — добро пожаловать в мой почтовый ящик, он есть на моём сайте внизу каждой страницы.