Re: Вопрос по С



Имеешь в виду различные реализации Си?
И соответственно разные аппаратные платформы?
угу
Дело не в длине, уверяю. Считайте, что выхода за пределы массива 100% не может быть. Но в случае с char он тем не менее происходит.


Платформа 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 разрядки пойти


в 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. я исходил из предположения, что всё так, как описано...

Народ, а сколько места в Линухе отводится под указатель? 4 или 2 байта?

Я напишу код, если ты готов пожертвовать своим Линуксом. А так смысла нет, нужно кое-что поменять в ядре, так просто не проверить. И вопрос только в том фича ли это С или gcc или баг того, чем я свой код компилирую.
8 или 4. Зависит от разрядности.

но свою копирующую функцию с ее вызовами можешь выложить, покрайней мере баг Си и баг проги найти постараюсь
Я напишу код, если ты готов пожертвовать своим Линуксом.
Давай код . Завтра проверю . Причём рискну не своим линуксом - а сервером (своего в принципе нет ). Естественно после консультации с нашими программерами и админом ..............

Дай мне файл mm/memory.c из исходников. Я там напишу все, что нужно. Там эта пресловутая функция копирования и находится.
Если Atilla файл не даст, я завтра напишу тут, что и как.
Я на работе с 15 . до 19 могу твой код кому-нибудь скормить для проверки и попробовать запустить .....................
ага, нашел... copy_page_range?
range это не то, видимо. Там конкретно одна страница должна копироваться. Ищи там 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, как указатели на заранее зарезервированную область памяти, работают по разному?