Программистское. Скучное.
Mar. 3rd, 2005 05:40 amПосле 5 лет тотальной Perl лоботомии я понял, что забыл С практически начисто... Провозился 2 дня с вылизыванием 80 строчек кода :( Но до сих пор не уверен, что сделал все правильно. Так что, если кто присоветует, что тут еще можно улучщить - пишите :) Да, если по скорости какие-то оптимизации - тоже :)
Да, код под FreeBSD5 :)
Кстати, не уверен, насколько верно передавать int a в функцию с void* ptr через &a, а потом приводить через *(int*)ptr. Но в теории, размера указателя может не хватить, чтобы поместить в него int(хотя до сих пор работало:)).
Да, код под FreeBSD5 :)
#include <errno.h>
#include <sys/types.h>
#include <sys/extattr.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
static struct {
int space;
const char *name;
size_t len;
}
extattr[] = {
{ EXTATTR_NAMESPACE_SYSTEM, “system.”, sizeof(“system.”) },
{ EXTATTR_NAMESPACE_USER, “user.”, sizeof(“user.”) },
};
ssize_t my_listxattr (int type, const void *arg, char *list, size_t size) {
ssize_t list_size, tot_size = 0;
int i, t, len;
char *buf;
/* Iterate through extattr(2) namespaces */
for(t = 0; t < sizeof(extattr)/sizeof(extattr[0]); t++) {
switch(type) {
case 0:
list_size = extattr_list_file((const char*)arg, extattr[t].space, list, size);
break;
case 1:
list_size = extattr_list_link((const char*)arg, extattr[t].space, list, size);
break;
case 2:
list_size = extattr_list_fd(*(int*)arg, extattr[t].space, list, size);
break;
default:
errno = ENOSYS;
return -1;
}
/* Some error happened. Errno should be set by previous call */
if(list_size < 0)
return -1;
/* No attributes */
if(list_size == 0)
continue;
/* XXX: Call with an empty buffer may be used to calculate
necessary buffer size. Unfortunately, we can't say, how
many attributes were returned, so here is the potential
problem with the emulation.
*/
if(list == NULL) {
/* For sure, at least one attribute exists. */
tot_size += list_size + extattr[t].len - 1;
continue;
}
/* Count necessary offset to fit namespace prefixes */
len = 0;
for(i = 0; i < list_size; i += list[i] + 1)
len += extattr[t].len - 1;
tot_size += list_size + len;
/* Buffer is too small to fit the results */
if(tot_size > size) {
errno = ERANGE;
return -1;
}
/* Shift the results back, so we can prepend prefixes */
buf = memmove(list + len, list, list_size);
for(i = 0; i < list_size; i += len + 1) {
len = buf[i];
strncpy(list, extattr[t].name, extattr[t].len);
strncat(list, buf + i + 1, len);
list += extattr[t].len + len;
}
size -= tot_size;
}
return tot_size;
}
ssize_t sys_listxattr (const char *path, char *list, size_t size)
{
return my_listxattr(0, path, list, size);
}
ssize_t sys_llistxattr (const char *path, char *list, size_t size)
{
return my_listxattr(1, path, list, size);
}
ssize_t sys_flistxattr (int filedes, char *list, size_t size)
{
return my_listxattr(2, &filedes, list, size);
}
int main(int argc, char *argv[]) {
char buf[1024];
ssize_t size;
int fd, i = 0;
//size = sys_listxattr(argv[1], buf, sizeof(buf));
fd = open(argv[1], O_RDONLY);
size = sys_flistxattr(fd, buf, sizeof(buf));
//size = sys_flistxattr(fd, NULL, 0);
printf("Len: %d\n", size);
for(i = 0; i < size; i += strlen(buf+i)+1) {
printf("%s\n", buf+i);
}
return 0;
}
Кстати, не уверен, насколько верно передавать int a в функцию с void* ptr через &a, а потом приводить через *(int*)ptr. Но в теории, размера указателя может не хватить, чтобы поместить в него int(хотя до сих пор работало:)).
no subject
Date: 2005-03-02 08:53 pm (UTC)no subject
Date: 2005-03-02 08:55 pm (UTC)Вообще я эту конструкцию на автомате писал, так что уже и не уверен :)
no subject
Date: 2005-03-02 08:58 pm (UTC)(no subject)
From:no subject
Date: 2005-03-03 01:13 am (UTC)Только вот текст постинга (не код) наводит на крамольную мысль, что сам автор кода не ведает, что творит :))))
no subject
Date: 2005-03-03 04:03 am (UTC)Я пытаюсь сэмулировать линуксячие функции на FreeBSD :) Может, в Линук эмулятор это дело заодно продать?
no subject
Date: 2005-03-03 02:04 pm (UTC)no subject
Date: 2005-03-03 03:35 pm (UTC)void f(void* p) {
int c = (int)p + 8;
}
int a= 10;
f((void*)a);
В качестве примера отсылаю к glib и макросам GINT_TO_POINTER() и POINTER_TO_GINT().
(no subject)
From:(no subject)
From:(no subject)
From:no subject
Date: 2005-03-03 06:21 pm (UTC)(no subject)
From:Я возьму вот этот кусочек, для начала:
Date: 2005-03-02 09:05 pm (UTC)я бы сделал так:extattr[] = { { EXTATTR_NAMESPACE_SYSTEM, “system.”, sizeof(“system.”) }, { EXTATTR_NAMESPACE_USER, “user.”, sizeof(“user.”) }, };Комфорт + меньшая вероятность ошибки. ;-)#define extattr_STRnLEN(str) str, sizeof(str) extattr[] = { { EXTATTR_NAMESPACE_SYSTEM, extattr_STRnLEN("system.") }, { EXTATTR_NAMESPACE_SYSTEM, extattr_STRnLEN("user.") } }; #undef extattr_STRnLENRe: Я возьму вот этот кусочек, для начала:
Date: 2005-03-02 09:09 pm (UTC)Пожалуйста
Re: Я возьму вот этот кусочек, для начала:
Date: 2005-03-03 01:07 am (UTC)злая собакамакрос".Не буду спорить, насчет традиции. Но в данном случае, ...
no subject
Date: 2005-03-02 09:31 pm (UTC)typedef union extattr_arg
{
const char *file;
const char *link;
int fd;
} extattr_arg;
ssize_t my_listxattr (int type, extattr_arg arg, char *list, size_t size) {
...
case 0:
list_size = extattr_list_file(arg.file, extattr[t].space, list, size);
break;
case 1:
list_size = extattr_list_link(arg.link, extattr[t].space, list, size);
break;
case 2:
list_size = extattr_list_fd(arg.fd, extattr[t].space, list, size);
break;
...
ssize_t sys_listxattr (const char *path, char *list, size_t size)
{
extattr_arg arg;
arg.file = path;
return my_listxattr(0, arg, list, size);
}
ssize_t sys_llistxattr (const char *path, char *list, size_t size)
{
extattr_arg arg;
arg.link = path;
return my_listxattr(1, arg, list, size);
}
ssize_t sys_flistxattr (int filedes, char *list, size_t size)
{
extattr_arg arg;
arg.fd = filedes;
return my_listxattr(2, arg, list, size);
}
no subject
Date: 2005-03-03 05:52 am (UTC)Но вот представь как аналогичная функциия для IRIX написана:
static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags);
Вот те path и filedes - это то что я через void* передаю :) А там - либо (1, 0), либо (0, 1) :)))
no subject
Date: 2005-03-02 09:34 pm (UTC)no subject
Date: 2005-03-03 05:52 am (UTC)no subject
Date: 2005-03-03 01:56 am (UTC)1. Хорошо бы функции extattr_list_* свести в массивчик (да, а первый параметр сделать именно union). Тогда вместо дурацкого switch был бы вызов функции из массива. Причем указатель в этом массиве, очевидно, вычисляется снаружи главного цикла. Вообще, у тебя хроническая болезнь - невынос инвариантов из циклов (да да, я в курсе, что-то может соптимизировать компилятор - но лучше не полагаться на волю случая...:)
2. Циклы от 0 до n менее эффективны, чем от n до 0. Потому как операция сравнения с 0 - дешевле. Типа for (i=n;--i>=0;)
3. Немного глупо каждый раз делать extattr[t] - надо просто указателем гулять по extattr.
no subject
Date: 2005-03-03 06:19 am (UTC)А на чем основана мысль, что с 0 сравнивать дешевле?
@@ -10,16 +10,16 @@
movl %esp,%ebp
subl $24,%esp
nop
- movl $10,-4(%ebp)
+ movl $0,-4(%ebp)
.p2align 4,,7
.L3:
- cmpl $0,-4(%ebp)
- jg .L5
+ cmpl $9,-4(%ebp)
+ jle .L5
jmp .L4
.p2align 4,,7
.L6:
.L5:
- decl -4(%ebp)
+ incl -4(%ebp)
jmp .L3
.p2align 4,,7
.L4:
Результат сравнения прямого и обратного цикла, скомпилированного в ассемблер :) Как видишь - одинаковый абсолютно код :)
А вот насчет указателя верно замечено :) Правда, опять же - придется тип вводить, чтобы такой указатель создать... Не хотелось бы namespace засорять :)
no subject
Date: 2005-03-03 07:46 am (UTC)1. wrapper можно заинлайнить (он же однострочный и простой). Это все compile-time время. Зато гарантировано константное (и небольшое - в случае инлайна) время вызова конечной функции - не if-then-elif-then-else... (еще и умноженное на кол-во проходов цикла!) Да и вообще архитектурно элегантно-выпендрежнее получается:)
2. Ты меня убил асмовским кодом... Эти уроды, чтобы с 0 сравнить - в стек его грузят? Тогда да, беру свои слова обратно про оптимальность цикла. И начинаю ругаться на gcc...:) Пойду покомпилирую что ли, поизучаю... Еще в древние времена всякие bcc/cl умели нормально с 0 на x86 сравнивать...
3. А указатель таки введи, для красоты-то:)
(no subject)
From:(no subject)
From:(no subject)
From:Это к вопросу о читаемости.
From:Re: Это к вопросу о читаемости.
From:Что ж, могу только посоветовать почитать Алана Голуба,
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:> 2. Циклы от 0 до n менее эффективны, чем от n до 0.
Date: 2005-03-04 05:33 am (UTC)Вообще конечно, данное правило очень специфично. Я бы им пользовался тольк тогда, когда нужно писать что-то жутко критичное по скорости выполнения. В противном случае, главное -- читаемость.
Re: > 2. Циклы от 0 до n менее эффективны, чем от n до 0.
From:Re: > 2. Циклы от 0 до n менее эффективны, чем от n до 0.
From:Я за читаемость!
From:Re: > 2. Циклы от 0 до n менее эффективны, чем от n до 0.
From:Я говорил о том, что ...
From:Re: Я говорил о том, что ...
From:Скажи, счет эл-ов тебе в этом цикле нужен?...
From:> Т.е. ркально там вкомпилена 2-ка
From:Re: > Т.е. ркально там вкомпилена 2-ка
From:И ты Брут?...
From:Re: > 2. Циклы от 0 до n менее эффективны, чем от n до 0.
From:Re: > 2. Циклы от 0 до n менее эффективны, чем от n до 0.
From:Re: > 2. Циклы от 0 до n менее эффективны, чем от n до 0.
From:Re: > 2. Циклы от 0 до n менее эффективны, чем от n до 0.
From:Re: > 2. Циклы от 0 до n менее эффективны, чем от n до 0.
From:no subject
Date: 2005-03-03 02:01 am (UTC)for(i = 0; i < list_size; i += len + 1) {
len = buf[i];
strncpy(list, extattr[t].name, extattr[t].len);
strncat(list, buf + i + 1, len);
list += extattr[t].len + len;
}
переделав в:
for(i = 0; i < list_size; i += len + 1) {
len = buf[i];
// меньше на проверку внутри, а строка у нас точно NUL-терминирована в известном месте
strcpy(list, extattr[t].name);
// не ищем конец строки перед добавлением в конец, потому как знаем где он
list += extattr[t].len;
// если в bsd есть stxcpy, то две следующие строчки меняются на него
strncpy(list, buf + i + 1, len-1); // а можно и memcpy в общем-то - будет ещё быстрее
list[len-1] = '\0';
list += len;
}
no subject
Date: 2005-03-03 10:17 am (UTC){ EXTATTR_NAMESPACE_SYSTEM, "system.", sizeof("system.")-1 },
...
for(i = 0; i < list_size; i += len + 1) {
len = buf[i];
strcpy(list, extattr[t].name);
list += extattr[t].len;
strncpy(list, buf + i + 1, len);
list[len] = '\0';
list += len + 1;
}
(no subject)
From:Ну вот, ты получил столько "feed-back"'а...
Date: 2005-03-04 06:02 am (UTC)Re: Ну вот, ты получил столько "feed-back"'а...
Date: 2005-03-04 06:04 am (UTC)Но это видимо со следующим релизом.