memset, 64 бита
64-битный мемсет
SYNOPSIS
#include <string.h>
void *
memset(void *b, int c, size_t len);
Мьсе, причем тут битность и битность чего?
перформанс плавает и его можно дотачивать под конкретную железку
http://www.hpc.ru/pda/board/index.php?t=77292
Мне кажется, такое понимание естественно, и гугль со мной согласен. К сожалению, ответ на свой вопрос я в гугле не нашел, но обнаружил, что сам вопрос задаю не только я.
ясно, спасибо
Вообще, обычный memset — он быстрый? Как он реализован?Я думаю, что по данному вопросу нужно использовать source в качестве documentation.
Лично я на практике получал то, что memset и memcpy работал медленнее чем обычный цикл. Производительность (по времени) падала на 1-2%. К тому же если включить параметр компиляции -funroll-loops или самому ручками развернуть цикл (т.к. gcc хоть и крут, но двойные \ тройные циклы он разворачивает не очень то оно будет весьма неплохо работать.
Да, задача именно такая. Спасибо
EXTERN_C void * __cdecl memset(void *d, int v, size_t c)
{
if ADDRESS) d) | c) & (sizeof(UINT) - 1 {
BYTE *pD = (BYTE *) d;
BYTE *pE = (BYTE *) ADDRESS) d) + c);
while (pD != pE)
*(pD++) = (BYTE) v;
}
else {
UINT *pD = (UINT *) d;
UINT *pE = (UINT *) (BYTE *) ADDRESS) d) + c);
UINT uv;
uv = UINT) (v & 0xff | UINT) (v & 0xff << 8);
/* Our processors are at least 32 bits
*/
uv |= uv << 16;
#if (_UINTSIZE == 64)
/* They might be 64 bits
*/
uv |= uv << 32;
#endif
while (pD != pE)
*(pD++) = uv;
}
return d;
}
Если адрас не выровнен или размер неудачный, то шлепается по байту, если выровнен, то готовится UINT значение и шлепается по 4\8 байт в зависимости от архитектуры.
это где UINT 64 битный?
UPD: Ох это какая-то экспериментальная ерь от мелкомягких...
Например, на NetBSD/amd64, NetBSD/sparc64, NetBSD/mips64, NetBSD/powerpc64.
---
"NetBSD is JIHBED!"
Это неправда, и простой взгляд на исходные тексты libc
прекрасно показывает это.
---
"Расширь своё сознание!"
> memset пишет 8 битMEMSET(3) Linux Programmer's Manual MEMSET(3)
Это неправда, и простой взгляд на исходные тексты libc
прекрасно показывает это.
NAME
memset - fill memory with a constant byte
SYNOPSIS
#include <string.h>
void *memset(void *s, int c, size_t n);
DESCRIPTION
The memset function fills the first n bytes of the memory area pointed to by s with the constant byte c.
RETURN VALUE
The memset function returns a pointer to the memory area s.
CONFORMING TO
SVr4, 4.3BSD, C89, C99, POSIX.1-2001.
SEE ALSO
bzero(3 swab(3 wmemset(3)
COLOPHON
This page is part of release 3.21 of the Linux man-pages project. A description of the project, and information about reporting bugs, can be found at http://www.ker-
nel.org/doc/man-pages/.
GNU 1993-04-11 MEMSET(3)
PS Мое скромное мнение: 1 байт есть 8 бит.
The memset function fills the first n bytes of the memory area pointed to by s with the constant byte c.Это как-то мешает в реализации писать по 32 или 64 бита?
> PS Мое скромное мнение: 1 байт есть 8 бит.
Оставайся при своём скромном мнении.
---
"Математик может говорить, что ему хочется,
но физик должен, хотя бы в какой-то мере, быть в здравом рассудке."
Чего чего я не понял?
Ну, приведи пример кода, инициализирующий массив int значениями 257 с помощью memset.
Автору, кстати, можешь воспользоваться fill из STL (<algorithm>).
/*
FUNCTION
<<memset>>---set an area of memory
INDEX
memset
ANSI_SYNOPSIS
#include <string.h>
void *memset(const void *<[dst]>, int <[c]>, size_t <[length]>);
TRAD_SYNOPSIS
#include <string.h>
void *memset(<[dst]>, <[c]>, <[length]>)
void *<[dst]>;
int <[c]>;
size_t <[length]>;
DESCRIPTION
This function converts the argument <[c]> into an unsigned
char and fills the first <[length]> characters of the array
pointed to by <[dst]> to the value.
RETURNS
<<memset>> returns the value of <[m]>.
PORTABILITY
<<memset>> is ANSI C.
<<memset>> requires no supporting OS subroutines.
QUICKREF
memset ansi pure
*/
#include <string.h>
#define LBLOCKSIZE (sizeof(long
#define UNALIGNED(X) long)X & (LBLOCKSIZE - 1
#define TOO_SMALL(LEN) LEN) < LBLOCKSIZE)
_PTR
_DEFUN (memset, (m, c, n
_PTR m _AND
int c _AND
size_t n)
{
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
char *s = (char *) m;
while (n-- != 0)
{
*s++ = (char) c;
}
return m;
#else
char *s = (char *) m;
int i;
unsigned long buffer;
unsigned long *aligned_addr;
if (!TOO_SMALL (n) && !UNALIGNED (m
{
/* If we get this far, we know that n is large and m is word-aligned. */
aligned_addr = (unsigned long*)m;
/* Store C into each char sized location in BUFFER so that
we can set large blocks quickly. */
c &= 0xff;
if (LBLOCKSIZE == 4)
{
buffer = (c << 8) | c;
buffer |= (buffer << 16);
}
else
{
buffer = 0;
for (i = 0; i < LBLOCKSIZE; i++)
buffer = (buffer << 8) | c;
}
while (n >= LBLOCKSIZE*4)
{
*aligned_addr++ = buffer;
*aligned_addr++ = buffer;
*aligned_addr++ = buffer;
*aligned_addr++ = buffer;
n -= 4*LBLOCKSIZE;
}
while (n >= LBLOCKSIZE)
{
*aligned_addr++ = buffer;
n -= LBLOCKSIZE;
}
/* Pick up the remainder with a bytewise loop. */
s = (char*)aligned_addr;
}
while (n--)
{
*s++ = (char)c;
}
return m;
#endif /* not PREFER_SIZE_OVER_SPEED */
}
Только хвостик чарами добивает...
Чего чего я не понял?Вопроса.
> Ну, приведи пример кода, инициализирующий массив int
> значениями 257 с помощью memset.
Вопрос не про то, как это сделать при помощи memset,
а про реализацию.
> Автору, кстати, можешь воспользоваться fill из STL
Если человек спрашивает про memset, то это не случайно.
---
"Vyroba umelych lidi, slecno, je tovarni tajemstvi."
Вопрос не про то, как это сделать при помощи memset,Ну тебя я не понимаю, а первоначальный вопрос я понял. Автор спрашивал можно ли заполнить память 64 битными "неделимыми" структурами, а вы мне, как я понимаю, говорите про то, что memset сдвигается по 32 (64) бита по памяти, но при этом заполняет все эти 32 (64) бита одним значением (unsigned char) c, используя побитовый сдвиг. Что есть скорее оптимизация "8-битной записи", нежели "не 8-битность записи".
а про реализацию.
Если человек спрашивает про memset, то это не случайно.Не случайно конечно, но я видел многих, кто просто-напросто ничего не знает об stl алгоритмах, а они порой полезны.
Всем спасибо
void *memset(void *s, int c, size_t n);объясните мне, почему второй аргумент имеет тип int, а не unsigned char ?
Hysterical raisins?
---
SINT VT SVNT AVT NON SINT
так исторически сложилось? то есть когда ввели эту функцию она была корректной (копировала целыми интами а со временем стала некорректной (стали по-байтно копировать?) или изначально наглючили в стандарте Си?
update: судя по стандарту Си глюк был внедрен при рождении языка
update: судя по стандарту Си глюк был внедрен при рождении языкаЭто не глюк, а "фича" C. Передача парамера char не отличается от передачи параметра int.
а если не отличается, то почему не сделали char? =) чтобы не было неявной конверсии в int ? типа у нас супер оптимизация в сях
вот спасибо, зеленыйТак конверсия в любом случае будет. Параметры char передаются в функцию int-ами.
а если не отличается, то почему не сделали char? =) чтобы не было неявной конверсии в int ? типа у нас супер оптимизация в сях
И так же float нет смысла делать, т.к. он "проапгрейдится" до double.
И так же float нет смысла делать, т.к. он "проапгрейдится" до double.на powerpc тоже проапгрейдится?
если не заглядывать в букву стандарта, на апгрейд float->double неиллюзорно намекает отсутствие отдельного спецификатора для float'ов в printf
На первом курсе у нас на информатике использовался ваткомовский компилятор и так если писать %f вместо %lf, вывод будет неправильный. Но скорее всего просто компилятор работал не по стандарту.
А все эти *фичи языка Си* скорее зависят от процессора.
(да, float-double в контексте va_args припоминается)
на powerpc тоже проапгрейдится?только что вот проапгрейдилось.
test1.c:
void f(float);
int main
{
const float y = 28.18;
f(y);
return 0;
}
test2.c:
#include <stdio.h>
void f(double x)
{
printf( "%f\n", x );
}
отчего слинковалось?
разве float и double не разные типы?
А они обязаны быть разными?
---
...Я работаю антинаучным аферистом...
ботаем C vs C++ mangling
Разными — обязаны. Иметь разный размер или внутреннее представление — нет. Т.е. в C++ это линковаться не должно.
ссылочку хочу на стандарт =)
Ну и еще в С нет перегрузки, поэтому ему продвинутый манглинг не нужен. Там для __cdecl достаточно совпадения имен функций, для __stdcall и __fastcall — имен и суммарного размера параметров (с учетом округлений и выравниваний, короче полное смещение ESP за счет параметров, еще точнее: что написать в ADD ESP,<X> вместо <X> после возврата из функции).
вот поковырял драфтик:
3.3.2.2 Function callsно не очень понял, это то или не то
....
If the expression that denotes the called function has a type that
does not include a prototype, the integral promotions are performed on
each argument and arguments that have type float are promoted to
double. These are called the default argument promotions. If the
number of arguments does not agree with the number of parameters, the
behavior is undefined. If the function is defined with a type that
does not include a prototype, and the types of the arguments after
promotion are not compatible with those of the parameters after
promotion, the behavior is undefined. If the function is defined with
a type that includes a prototype, and the types of the arguments after
promotion are not compatible with the types of the parameters, or if
the prototype ends with an ellipsis ( ", ..." the behavior is
undefined.
If the expression that denotes the called function has a type that
includes a prototype, the arguments are implicitly converted, as if by
assignment, to the types of the corresponding parameters. The
ellipsis notation in a function prototype declarator causes argument
type conversion to stop after the last declared parameter. The
default argument promotions are performed on trailing arguments. If
the function is defined with a type that is not compatible with the
type (of the expression) pointed to by the expression that denotes the
called function, the behavior is undefined.
А, ты про это стандарт спрашивал. Ну, я не гуру стандарта, надо будет распечатать в толчок как-нибудь
потому что появлялась параллельно с фортраном и задача там ставилась только не пересекаться с фортраном.откуда это известно? и в чём польза от "не пересечения"?
и в чём польза от "не пересечения"?Ну как, по-моему очевидно: чтобы можно было не заморачиваясь использовать оба языка. Например, чтобы не добавлять требования к программам на фортране не иметь функций с именем "main".
откуда это известно?Читал в статье про устройство и эволюцию линкеров. К сожалению, ссылку найти не могу.
и в чём польза от "не пересечения"?начали бы влинковывать фортан в сишные проги и в новом стандарте c++0x пришлось бы его поддерживать (слава обратной совместимости)
Ну как, по-моему очевидно: чтобы можно было не заморачиваясь использовать оба языка. Например, чтобы не добавлять требования к программам на фортране не иметь функций с именем "main".а в чём проблема в программах на фортране иметь main? Сишные библиотеки, которые захочется линковать в этот фортран, не будут иметь main, очевидно.
> не заморачиваясь
не-не-не. сейчас, чтобы нормально линковать c-fortran, нужно в Си добавлять подчёркивания к прототипам. Разве это "не заморачиваясь"? А был бы одинаковый мэнглинг, извращаться бы не пришлось.
а в чём проблема в программах на фортране иметь main? Сишные библиотеки, которые захочется линковать в этот фортран, не будут иметь main, очевидно.Ну а если наоборот, линковать фортрановские либы в C?
> не заморачиваясьИзначально не было мэнглинга, его потом добавили как раз, чтобы пространства имен C и фортрана не пересекались. И как раз имена с подчеркиваниями были зарезервированы для фортрана.
не-не-не. сейчас, чтобы нормально линковать c-fortran, нужно в Си добавлять подчёркивания к прототипам. Разве это "не заморачиваясь"? А был бы одинаковый мэнглинг, извращаться бы не пришлось.
А "тогда" еще было и очень весомое ограничение на длину декорированного имени (что-то около 8ми символов что позволяло в итоге звать из фортрана фактически только функции не длинее 6 символов в имени.
А так можно по идее ожидать чего-нибудь типа extern "FORTRAN"
С функцией main? Тогда нужно библиотеки после объектных файлов указывать (что соответствует обычной практике) и main из сишного объектного файла победит.
Я не вижу тут ничего фортран-специфичного. Точно так же в программе на Си не должно быть externally-visible функций с именами, совпадающими с именами функций из линкующихся написанных на Си библиотек.
В слинкованной статье я сходу не вижу рационального объяснения появления такого_ фортрановского мэнглинга. Вот это:
As a particularly egregious example, this Fortran program would for quite a few years crash an OS/360 system:вообще абзац. Вместо того, чтобы пофиксить ОС и дать программистам стрелять себе в ногу, изобрели какое-то извращение. Точно так же в наши дни вызов __libc_start_main из пользовательского кода вызывает бесконечную рекурсию, и кого это парит?
CALL MAIN
END
MAINи
__libc_start_mainВторое вообще как-то боязно вызвать по определению.
Я не вижу тут ничего фортран-специфичного. Точно так же в программе на Си не должно быть externally-visible функций с именами, совпадающими с именами функций из линкующихся написанных на Си библиотек.Ну в статье было написано именно про стандартные библиотеки языков, которые разрабатывались изначально некоторое время независимо, и похоже, что у людей все-таки были причины сократить эффективную длину имени функции до 7 и 6ти для C и фортрана соответственно.
Ну и еще там написано про альтернативный подход.
Ну ты сравнил, конечно,Ну и переделали бы рантайм фортрана, чтобы он начинался не с MAIN, а с __libfortran_start_main, было бы одинаково боязно =)
MAIN — функция из C, ее в рантайме фортрана и так нет.
CALL MAIN
END
вообще не линковалась бы. Или я неправильно понял тот пассаж?
А, блин. Это я виноват, давно не читал статью. Там написано, что она как раз была фортрановская. Извиняюсь за запутывание. Сейчас перечитаю вопрос
Ну и переделали бы рантайм фортрана, чтобы он начинался не с MAIN, а с __libfortran_start_main, было бы одинаково боязно =)Ну типа так и сделали, просто замутили декорирование. Вроде я понял, там декорировали именно из-за специальных функций фортрана, которые лежали в библиотечках и явно в коде на фортране нигде не встречались. Их приходилось обходить как фортрановцам, так и сишникам.
насколько я понимаю, это фишка libc, связанная с EOF etc, т.е. идеей возврата кода ошибки, для возврата которой надо больше битов (а остальных местах сделали для единообразия , что имхо правильно)
void *memset(void *s, int c, size_t n);
объясните мне, почему второй аргумент имеет тип int, а не unsigned char ?
ну и какую ошибку ты хочешь вернуть memset'у?
gcc 4.3, watcom 1.8
printf("%f\n", x);
movss -4(%rbp %xmm0
cvtps2pd %xmm0, %xmm0
movl $.LC1, %edi
movl $1, %eax
call printf
Компилировал с -O0 для пущей наглядности.
Сие намекает нам на то, что %f все же соответствует типу double (как и написано в пункте 8 параграфа 7.19.6.1 стандарта ISO9899-C99; то же самое написано и в манах по printf а ты сделал ошибочное утверждение.
сие также намекает, что float несоответствует double, ибо в соответствие его приводит инструкция cvtps2pd
сие намекает, что вещественная арифметика, проводимая на MMX регистрах или регистрах сопроцессора, приводится к размерам регистров, которые 80 бит = long double.xmm0 - SSE регистр
xmm0 - 128-битный регистр
xmm0 может хранить как несколько 32-битных, так и несколько 64 битных вещественных чисел, но не 80- и не 128-битные.
сие также намекает, что float несоответствует double, ибо в соответствие его приводит инструкция cvtps2pd
Конечно, не соответствует.
Конечно, приводится инструкцией cvtps2pd
Потому что в функцию-то он передается как double.
О чем и говорили выше, но ты начал это опровергать, делая неверные утверждения в процессе.
на MMX регистрах ... приводится к размерам регистров, которые 80 битАйси на тебя нет. MMX регистры конечно занимают младшие 64 бита регистров сопроцессора, но преобразования до 80 бит не происходит iirc
размер регистров относился ко второй части предложения, а именно - к FPU.
UINT то шлепается, но у него все байты одинаковые, а нужно чтобы были разные.
UINT то шлепается, но у него все байты одинаковые, а нужно чтобы были разные.Ну суть примерно в том, что мемсет в любом случае сделает тот же цикл, что и у топикстартера )
Оставить комментарий
dimi61
Есть ли быстрый 64-битный мемсет? Вообще, обычный memset — он быстрый? Как он реализован?