Re: Вопрос по С
У них же длина разная ... если мне не изменяют мои познания в С
в размерах инт и чар?
изменяют. может быть разной
Имеешь в виду различные реализации Си?
И соответственно разные аппаратные платформы?
угу
Дело не в длине, уверяю. Считайте, что выхода за пределы массива 100% не может быть. Но в случае с char он тем не менее происходит.
код в студию
Ну на пне враде как char это 1 байт, а инт толи 2 толи 4... скорее 2.
Платформа Linux, компилятор gcc.
Платформа линукс еще ничего не говорит..... он же может быть на разных архитектурах стоять
А у них длина как правило, а может и всегда разная !
Поэтому... а+1 и в+1 - это разные вещи... т.к. б+1 может быть равно а+2.ж
З.Ы. надеюсь не наврал
char arr[1000];
void copy_arr(void* arr1, void* arr2, long size) {
long count;
unsigned long from = (unsigned long*) arr2;
unsigned long to = (unsigned long*) arr1
count = size / sizeof(long);
далее тупое копирование, алгоритм 100% рабочий, я его просто скопировал.
}
void do_something_bad(void* arr1) {
if (condition) {
copy_arr(arr, arr1, 1000);
}
}
Дело не в длине, я размер заведомо достаточный ставил, все-равно для char падало. Единственное, причина не обязательно в С как таковом: ошибка была не в прикладной программе. Просто вдруг я чего то важного про С не знаю.
Ты ж спросил в чем разница... а не почему падает
мне кажется дело в преобразовании в unsigned
Слушай... а это наормальноЮ, что в одном месте unsigned long а в другом просто long?
А в каком месте падает то?
скорее 2.
Ты чего? Это было до революции...
Сейчас все на 32 разрядах(старье не трогать)...
Скоро, должны 64 разрядки пойти
спасибо любимой Микрософт за Int_16, int_32, int_64
в unsigned* преобразуются void*. А проблема в том, что при замене char на long все работает, а для char'а - page_fault (размер массива одинаковый). Причем адресная арифметика есть только в функции копирования, остальное только преобразования типов.
Используй вместо copy_arr стандартную функцию memcpy(void* to, void* from, unsigned int size).
все 1С с его
Для СчетчикЦикла По Условие Цикл
//Делаем что то
КонецЦикла;
а ты компилируешь на no_opt? с компилятора станется прооптимизировать...
Int_16, int_32, int_64
Это эмуляция...
Сам сайзоф(инт) = маш.слово...
я знаю
Или там очень много ошибок...
Покажи его что ль
Всё-таки реальный фрагмент кода, который себя неправильно ведёт, поможет больше.
unsigned long from
А там не unsigned long * from должно стоять?
unsigned long * from
А что такое From?
Dtlm (unsigned long *) - это просто приедение типов, т.к. в параметрах Void*
Один зоркий человек нашелся
#include <fogoten.h> :)
template <class T>
void copy_arr( T *arr1, T *arr2, long size)
{
// memcopy or memcpy, poriadok arr ne pomnu
memcpy(arr1,arr2,size);
}
count = size / sizeof(long);
Падает при копировании в самом конце массива (причем не глючного, а из которого копируется) на границе двух страниц (дело происходит в ядре, а не в user mode). Функцию менять бессмысленно, поскольку а) эта работает для других типов б) она самая что ни на есть стандартная, я ее просто скопировал из другого места. Я просто думал, что дело в том, что я не знаю что-то о С. Все таки char[] это строка, может с ней какие то особые действия выполняются.
считай это опечаткой
Кроме особенностей оптимизатора, что-то не приходит больше в голову других причин, почему может не работать.
unsigned long* from = (unsigned long*) arr2;
unsigned long* to = (unsigned long*) arr1
а не
unsigned long from = (unsigned long*) arr2;
unsigned long to = (unsigned long*) arr1
2. Тебе точно надо изобретать велосипед? memcpy тебя не устраивает?
3. Как ты дальше исползуешь count?
4. char[] - это не строка. char[10] ничем сакральным кроме выделенной длинны в памяти не отличается от int[10].
void copy_page(void* _to, void* _from, long count) {
unsigned long* to = (unsigned long*) _to;
unsigned long* from = (unsigned long*) _from;
count /= (sizeof(unsigned long*)*4)
do {
unsigned long a, b, c, d;
a = from[0];
b = from[1];
c = from[2];
d = from[3];
count--;
from += 4;
to[0] = a;
to[1] = b;
to[2] = c;
to[3] = d;
to += 4;
} while (count);
}
Я повторяю проблему. Все работает, если заменить char на long (с соответствующим изменением длины массива). С char падает. Тут дело или в каких то особенностях С или в чем то еще, а в чем именно даже предположить не могу.
Тебе надо понять, что происходит, или сделать, чтоб работало?
а зачем такой изврат?
Что происходит. Чтобы работало нужно заменить char на long. Меня такая фигня очень смущает, если честно. Ведь это же не С++, где все что угодно может быть, а предсказуемый С. Но факт фактом char не работает вообще никак даже с намного большей длиной массива - возникает page fault. А его не должно быть в принципе, поскольку память заранее зарезрвирована.
Это не от меня зависит. Так надо.
Приведи вариант с char (который не работает)
так всё-таки, если скомпилировать без оптимизации, падает?
что можно сделать:
1. откомпилировать этот кусок без оптимизации, останется ли проблема?
2. поискать отличия в ассемблерном коде, сгенерированном компилятором для char и для int
3. попробовать воспроизвести проблему на искусственном примере в user level, тогда ты сможешь показать полный фрагмент кода какому-нибудь гуру
Он точно такой же только массив объявлен с char: char arr[1000]. Вполне возможно, что глюк в компиляторе или еще где, так что меня интересует только одно: не встречался ли кто то с похожей ситуацией, когда причина бага была в массиве char и исчезала, если использовать для массива другой тип.
2 .10 : memcpy использовать не могу - я не должен испортить стек вызовами функций или локальными переменными. В примере это не так для простоты. Насчет посмотреть код в ассемблере - может и поможет, но я того ассемблера вообще не знаю, это не Intel и тулзы для просмотра не факт, что есть. Отключить оптимизацию - попробую, если она есть.
твоя функция copy_arr, копирует count * sizeof(long) байт = 4*count байт
Для того, чтобы версия с char работала также, как версия с int. надо увеличить размер массива char-ов в 4 раза по сравнению с int-овой версией (если плохо чувствуешь, что такое память, то увелить лучше в 10, не ошибешься).
т.е. если ты пишешь int a[1000] и все работает, то в версии с char-ом должно быть char a[4 * 1000];, чтобы тоже все работало.
восколько раз ты делаешь массив с char-ами больше, чем с int-ами?
а unsigned long a, b, c, d разве не мешают?
> тулзы для просмотра не факт, что есть
генерировать: gcc -S
просматривать: less, vim, etc.
вообще встречался, оптимизатор char * и int * может по-разному обрабатывать
но там была проблема с aliasing, к твоему случаю никак не подходит вроде
К сожалению, причина не в этом. Считай, что копируется ровно столько байтов (или даже меньше сколько в массиве char.
к сожалению, по коду я этого не вижу
На самом деле, если не жалко свой Linux попробовать воспроизвести ошибку очень просто. Даже писать ничего почти не нужно - у меня падало при копировании 0-й страницы в свой буфер, причем, что прикольно, если считать страницу с диска в тот же буфер, то все было ОК. Так что проблема, возможно, действительно в aliasинге.
Поверь мне на слово. Размер массива я проверил в первую очередь и даже увеличил его в несколько раз (в 8 но это не помоголо, поскольку размер не зависел от long, а был заранее зафиксирован. Т.е. мне нужно было 1000 байт, я написал char arr[8000].
не понял
то есть _from == (void *) 0 ?
там же guard page, что тогда удивительного
еще раз, покажи функцию целиком, и при каком вызове она работает, а при каком - нет. желательно все константы и операторы указать, сорца мы не своруем
Нет не 0. 0-й страницы по виртуальному адресу - это начало 3-го гигабайта для Intel. На самом деле может была и не нулевая, а первая - это не важно. Кроме того, при long все работало.
походу Савкин прав, и надо смотреть асм...
а ты проверял что ли?.. у меня ща и винда под рукой есть и линух, можно просто проверить, если действительно ошибок не видно
P.S. я исходил из предположения, что всё так, как описано...
а у меня такое предположение, что человек где-то сначала забыл на sizeof умножить, а потом забыл перекопилять. А сейчас молчит, т.к. ошибку осознал и стало стыдно
Народ, а сколько места в Линухе отводится под указатель? 4 или 2 байта?
вот бы некоторым всё опошлить
Я напишу код, если ты готов пожертвовать своим Линуксом. А так смысла нет, нужно кое-что поменять в ядре, так просто не проверить. И вопрос только в том фича ли это С или gcc или баг того, чем я свой код компилирую.
8 или 4. Зависит от разрядности.
но свою копирующую функцию с ее вызовами можешь выложить, покрайней мере баг Си и баг проги найти постараюсь
Я напишу код, если ты готов пожертвовать своим Линуксом.
Давай код . Завтра проверю . Причём рискну не своим линуксом - а сервером (своего в принципе нет ). Естественно после консультации с нашими программерами и админом ..............
Дай мне файл mm/memory.c из исходников. Я там напишу все, что нужно. Там эта пресловутая функция копирования и находится.
Если Atilla файл не даст, я завтра напишу тут, что и как.
Я на работе с 15 . до 19 могу твой код кому-нибудь скормить для проверки и попробовать запустить .....................
ага, нашел... copy_page_range?
range это не то, видимо. Там конкретно одна страница должна копироваться. Ищи там from[0] в начале файла.
ни одного файла memory.c со строкой from[0] не нашлось
Блин, облажался. Copy не в этом файле, а где не помню. Где-то в районе copy_user_highpage. Но я и так напишу. wait a minute.
//long buffer[PAGE_SIZE/sizeof(long)];
char buffer[PAGE_SIZE];
void copy_page(void* _to, void* _from, long count) {
unsigned long* to = (unsigned long*) _to;
unsigned long* from = (unsigned long*) _from;
int flag;
count /= (sizeof(unsigned long*)*4);
local_irq_save(flag);
do {
unsigned long a, b, c, d;
a = from[0]; b = from[1];
c = from[2]; d = from[3];
count--;
from += 4;
to[0] = a;
to[1] = b;
to[2] = c;
to[3] = d;
to += 4;
} while (count);
local_irq_restore(flag);
}
void do_func(void* data, int mode) {
// Nothing
}
void do_work(void* data, int mode) {
if (mode == 1) {
copy_page(buffer, data, PAGE_SIZE);
do_func(buffer, mode);
} else {
do_func(data, mode);
}
}
void my_func(void) {
struct page* page;
long i = 100; // any number you want
page = &mem_map[0];
while (i) {
do_work(page_address(page 1);
i--;
page++;
}
}
Вставить это можно в тот же memory.c. Если жертвовать Линуксом, то my_func нужно вставить в init/main.c в функцию init перед execve(..)'ями. Разница между работающим и неработающим вариантами в первой строчке. C char не работает , хотя у тебя может и заработает.
Вот тут сразу видно не правильно. Навекрное имелось виду count /= (sizeof(unsigned long)*4); Тем более count / (sizeof(unsigned long)*4) - не всегда целое число, если размер дан в char-ах.
что такое mem_map?
просто чтобы все копировалось, count должно быть кратно 16. Но если это не так, то просто не вся страница скопируется, выход не должен произойти
Это опечатка. Кроме того, размер ulong и указателя одинаковый там, где возникала ошибка. Число будет делиться по определению. Размер массива всегда степень двойки - 4096 байт.
mem_map - глобальная переменная. Она определена в самом начале memory.c, можешь посмотреть. По типу это массив struct page'ей.
//char buffer[PAGE_SIZE];
long buffer[PAGE_SIZE/sizeof(long)];
void copy_page(void* _to, void* _from, long count)
{
unsigned long* to = (unsigned long*) _to;
unsigned long* from = (unsigned long*) _from;
int flag;
count /= (sizeof(unsigned long*)*4);
do {
unsigned long a, b, c, d;
a = from[0]; b = from[1]; c = from[2]; d = from[3];
count--;
from += 4;
to[0] = a;
to[1] = b;
to[2] = c;
to[3] = d;
to += 4;
} while (count);
}
void do_work(void* data, int mode)
{
if (mode == 1)
{
copy_page(buffer, data, PAGE_SIZE);
}
}
void my_func(void)
{
double data[10000];
long i = 100;
do_work(data, 1);
}
ЗЫ под линухом gcc это тоже все съела и все нормально работало, не упало...
траблы могут быть с этим массивом mem_map, его размером и содержимым. А вообще, все это имхо нафиг не нужно, т.к. есть memcpy, которую умный компилятор (icl, cl etc) может превратить в нормальные SIMD-инструкции.
Оставить комментарий
JERRY
В чем заключается разница междуchar a[100];
и
int b[100];
Разница в том смысле, что a и b, как указатели на заранее зарезервированную область памяти, работают по разному?