2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу Пред.  1, 2, 3, 4  След.
 
 Re: СИ. Указатели. Можно ли к указателю прибавить любое число?
Сообщение31.08.2015, 07:04 


02/10/12
308
В stdint.h off_t не упоминаются. И ssize_t не упоминаются.
Пример записи в stdint.h
Используется синтаксис C
//<stdint.h>
/* Limit of `size_t' type.  */
# if __WORDSIZE == 64
#  define SIZE_MAX      (18446744073709551615UL)
# else
#  define SIZE_MAX      (4294967295U)
# endif
 

В limits.h off_t тоже не упоминаются.
Используется синтаксис C
//<limits.h>
/* Minimum and maximum values a `signed int' can hold.  */
#  define INT_MIN   (-INT_MAX - 1)
#  define INT_MAX   2147483647
 

В stdlib.h тоже нет подходящих.
Файлы сложные, многое я в них не понимаю.

Если в функцию из предыдущего моего сообщения вместо off_t всюду
подставить int, т. е. сделать преобразование в int-число, и
применить INT_MIN и INT_MAX, то да, работает. Может, соответствующих
констант для off_t не существует, может, про них забыли.

И в любом случае всё же прошу ответить на вопрос: нет ли в этом коде подвоха
Используется синтаксис C
    off_t MY_MIN_OFF_T, MY_MAX_OFF_T = 1;

    while((MY_MAX_OFF_T << 1) > 0){ MY_MAX_OFF_T = (MY_MAX_OFF_T << 1) + 1;}
    MY_MIN_OFF_T = -MY_MAX_OFF_T;
 

И можно ли последнюю строку заменить на эту, чтоб еще максимальное
отрицательное число взять?
Используется синтаксис C
    MY_MIN_OFF_T = -MY_MAX_OFF_T - 1;
 

 Профиль  
                  
 
 Re: СИ. Указатели. Можно ли к указателю прибавить любое число?
Сообщение31.08.2015, 07:37 


11/12/14
893
oleg_2 в сообщении #1049406 писал(а):
нет ли в этом коде подвоха


Да, здесь "внаглую" используется переполнение знакового числа - а стандарт как мы помним хочет попасть под все возможные реализации этого дела и объявляет такие вещи как UB.
Паниковать не стоит - во первых - вряд ли вы когда нибудь столкнётесь с аппаратной начинкой где сей код будет неверным - дополнение до двух плотно вошло в мир современных компьютеров. Однако, если охота прямо таки перестраховаться - просто выделите такой код в "платформенно-зависимые файлы" (чисто для красоты пока, т.к. сомневаюсь что когда либо потребуется действительно их в таком ключе использовать). Кроме того здесь сам этот код в рантайме вычисляющий что-то просто не нужен - идёте, смотрите что такое off_t и делаете на основании этого пару своих дефайнов.

 Профиль  
                  
 
 Re: СИ. Указатели. Можно ли к указателю прибавить любое число?
Сообщение31.08.2015, 08:06 


02/10/12
308
Используется синтаксис C
  После последнего прохода цикла:
    |0|1|1|1|1|1|   MY_MAX_OFF_T

    while((MY_MAX_OFF_T << 1) > 0) -условие цикла

    |0|1|1|1|1|1|  (MY_MAX_OFF_T << 1) -операция
    |1|1|1|1|1|0|  -результат операции < 0, цикл не выполняется.
 

Непонятно, почему простой сдвиг на 1 бит - UB?
Или после сдвига проверка на "больше нуля" - UB?

 Профиль  
                  
 
 Re: СИ. Указатели. Можно ли к указателю прибавить любое число?
Сообщение31.08.2015, 08:18 


11/12/14
893
oleg_2 в сообщении #1049409 писал(а):
Непонятно, почему простой сдвиг на 1 бит - UB?


Почитайте https://ru.wikipedia.org/wiki/%D0%94%D0 ... B%D0%B0%29
Обратите внимание, что возможны теоретически разные способы представления отрицательных чисел.

 Профиль  
                  
 
 Re: СИ. Указатели. Можно ли к указателю прибавить любое число?
Сообщение02.09.2015, 09:25 


02/10/12
308
aa_dav в сообщении #1049407 писал(а):
Да, здесь "внаглую" используется переполнение

Вот нашел.
http://www.viva64.com/en/d/0225/print/
This is how the C++11 standard describes shift operators' work:

2. The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are
zero-filled. If E1 has an unsigned type, the value of the result is E1 * 2^E2,
reduced modulo one more than the maximum value representable in the result type.
Otherwise, if E1 has a signed type and non-negative value, and E1*2^E2 is
representable in the result type, then that is the resulting value; otherwise,
the behavior is undefined.

Используется синтаксис C
    off_t max = 1;
    while((max << 1) > 0){ max = (max << 1) | 1;}
 

Как я понимаю, в данном случае E1*2^E2 не представимо типом результата, т. к.
становится отрицательным, и, стало быть, undefined behavior. Обложили со всех
сторон.
aa_dav в сообщении #1049407 писал(а):
идёте, смотрите что такое off_t и делаете на основании этого пару своих дефайнов

Я даже на своем компьютере не нашел, что такое off_t, сложно. Надо
чтоб само собой работало, без помощи человека.

Вы, venco, предложили использовать беззнаковый
тип того же размера. Но я же заранее не знаю этот тип, это может быть long int
или long long int. А для off_t нет сопряженного типа uoff_t.

А если через sizeof? Примерно так:
Используется синтаксис C
    int i, bits = sizeof(off_t) * 8;
    off_t max = 1;
    for(i=0; i < (bits - 2); i++){ max = (max << 1) | 1;}
 


Офтоп (а в настоящем офтопе код не отображается)
Я даже вспомнил случай с UB при переполнении, он заключается в том, что в
этом куске кода (ниже), при компиляции с -O3, если s переполняется
и становится отрицательным, то проверка if(s < 0) не работает. Без
оптимизации работает. Наверно, это и есть маленькое UB.
Используется синтаксис C
    s=0;
    while(*p1>='0' && *p1<='9'){
        s = (s * 10) + ((*p1++) - '0');
    }
    if(s < 0){}
 

 Профиль  
                  
 
 Re: СИ. Указатели. Можно ли к указателю прибавить любое число?
Сообщение02.09.2015, 14:08 
Заслуженный участник
Аватара пользователя


01/09/13
4656
oleg_2 в сообщении #1049885 писал(а):
А для off_t нет сопряженного типа uoff_t.

size_t?

 Профиль  
                  
 
 Re: СИ. Указатели. Можно ли к указателю прибавить любое число?
Сообщение12.09.2015, 15:20 


27/02/09
253
oleg_2 в сообщении #1049885 писал(а):
А если через sizeof? Примерно так:
Используется синтаксис C
int i, bits = sizeof(off_t) * 8;
off_t max = 1;
for(i=0; i < (bits - 2); i++){ max = (max << 1) | 1;}
 
В стандартных заголовках написали бы что-то вроде:
Используется синтаксис C
#define MAX_OFFSET ( ( ( off_t )1 << ( sizeof( off_t ) * 8 - 1 ) ) - 1 )

 Профиль  
                  
 
 Re: СИ. Указатели. Можно ли к указателю прибавить любое число?
Сообщение12.09.2015, 16:24 
Заслуженный участник


20/08/14
11780
Россия, Москва
Интересно, а поддерживает ли язык С числа с несколькими знаковыми битами? Например с двумя знаковыми битами числа могут возникать как результат умножения двух знаковых чисел в прямом коде, если не применять специальные меры (впрочем везде применяются). Для таких кодировок метод с sizeof напрямую не подойдёт. Ладно, это фантазия. :-)

А в заголовках думаю лучше использовать такое определение (не трогать знаковый бит вообще):
Используется синтаксис C
#define MAX_OFFSET ( ( ( ((off_t)1 << (sizeof(off_t) * 8 - 2)) - 1) << 1) | 1)

 Профиль  
                  
 
 Re: СИ. Указатели. Можно ли к указателю прибавить любое число?
Сообщение13.09.2015, 07:17 


11/12/14
893
В стандартных заголовках так и пишут:
Используется синтаксис C++
#define INT_MAX         2147483647
#define INT_MIN         (-INT_MAX-1)
 

Там где невозможно сделать platform independent code его просто не делают и всё.

 Профиль  
                  
 
 Re: СИ. Указатели. Можно ли к указателю прибавить любое число?
Сообщение14.11.2015, 15:14 
Аватара пользователя


07/02/12
1438
Питер
oleg_2 в сообщении #1048844 писал(а):
Указатель p1 может на один байт выйти за край массива вправо, и при этом
еще и использоваться в адресных выражениях типа (p1 < p2).
случится, то плохо.

на практике проблем не будет, даже если выйдете на несколько байт. в теории указатель может вылезти не только за пределы массива, но и адресного пр-ва - т.е. переполниться и тогда неравенство не сработает. собственно это и есть unpredictable behavior, т.к. массивы не могут заканчиваться последним байтом адр. пр-ва и начинаться 0-вым.

oleg_2 в сообщении #1048844 писал(а):
А если, скажем, компилятор на операцию с указателем вставит
какую-нибудь защиту от переполнения регистра, и если такое переполнение

Не вставит. В С++ указатели - это целые числа, с ними можно свободно работать, не боясь выхода за пределы массивов, что на практике часто используется.

В частности, можно конвертировать указатель в число и назад примерно следующей конструкцией:

int i = (char *)p - (char *)NULL;
char *p = (char *)NULL + i;

 Профиль  
                  
 
 Re: СИ. Указатели. Можно ли к указателю прибавить любое число?
Сообщение14.11.2015, 18:04 
Заслуженный участник


04/05/09
4587
bondkim137, пожалуйста, перечитайте всё обсуждение. Тут было сказано больше, чем просто "будут проблемы или нет".
И не давайте откровенно вредных советов, типа сохранения указателя в int.

 Профиль  
                  
 
 Re: СИ. Указатели. Можно ли к указателю прибавить любое число?
Сообщение14.11.2015, 18:06 
Заслуженный участник
Аватара пользователя


30/01/06
72407
venco в сообщении #1073419 писал(а):
И не давайте откровенно вредных советов, типа сохранения указателя в int.

А что, не влезет?

 Профиль  
                  
 
 Re: СИ. Указатели. Можно ли к указателю прибавить любое число?
Сообщение14.11.2015, 18:47 
Заслуженный участник


04/05/09
4587
Munin в сообщении #1073421 писал(а):
venco в сообщении #1073419 писал(а):
И не давайте откровенно вредных советов, типа сохранения указателя в int.

А что, не влезет?
В современных условиях с большой вероятностью не влезет. На 64-битных платформах int часто имеет размер 32 бита.

 Профиль  
                  
 
 Re: СИ. Указатели. Можно ли к указателю прибавить любое число?
Сообщение14.11.2015, 21:08 
Аватара пользователя


07/02/12
1438
Питер
venco в сообщении #1073419 писал(а):
И не давайте откровенно вредных советов, типа сохранения указателя в int.

Я Вас прошу не корючкотворствовать, понятно, что в 64-разрядных приложениях для подобных транзитивных операций необходимо применять 64-х разрядный int.

И я нисколько не поддержу Вас в том, что сериализация указателя в целое число - идея вредная. Указатели, как и целые числа, упорядочены и аддитивны (через целые числа) что позволяет работать с ними, как ключами различных структур - в частности, деревьев и хешей, расчитывать по указателям размеры частей массивов, экстрполировать эти данные для вычислений (в том числе нелинейных) указателей и т.д. и т.п.

-- 14.11.2015, 21:21 --

venco в сообщении #1049090 писал(а):
По стандарту переполнение в арифметике со знаковыми числами - undefined behavior. И тоже никто не парится. Хотя недавно оптимизатор GCC так улучшили, что он как раз и сделал то, про что я писал - выкинул кусок кода, в котором было переполнение с int.


Можно по-подробнее? Какой кусок кода выкинули? На моем веку в C++ знаковое представление целых чисел было всегда дополнением до двойки - другой экзотики никогда не встречал. Тогда сложение и вычитание знаковых и беззнаковых чисел без насыщения никак не отличаются. И на практике все этим пользуются.

-- 14.11.2015, 21:29 --

 Профиль  
                  
 
 Re: СИ. Указатели. Можно ли к указателю прибавить любое число?
Сообщение14.11.2015, 22:09 
Заслуженный участник


04/05/09
4587
bondkim137 в сообщении #1073461 писал(а):
venco в сообщении #1073419 писал(а):
И не давайте откровенно вредных советов, типа сохранения указателя в int.

Я Вас прошу не корючкотворствовать, понятно, что в 64-разрядных приложениях для подобных транзитивных операций необходимо применять 64-х разрядный int.

И я нисколько не поддержу Вас в том, что сериализация указателя в целое число - идея вредная. Указатели, как и целые числа, упорядочены и аддитивны (через целые числа) что позволяет работать с ними, как ключами различных структур - в частности, деревьев и хешей, расчитывать по указателям размеры частей массивов, экстрполировать эти данные для вычислений (в том числе нелинейных) указателей и т.д. и т.п.
Проблема в том, что выбранный вами метод преобразования в стандарте определён как "undefined behavior", а какие из этого могут последовать проблемы, в этой теме как раз и обсуждалось.
А правильный по стандарту метод -
Код:
uintptr_t address = reinterpret_cast<uintptr_t>(ptr)


bondkim137 в сообщении #1073461 писал(а):
venco в сообщении #1049090 писал(а):
По стандарту переполнение в арифметике со знаковыми числами - undefined behavior. И тоже никто не парится. Хотя недавно оптимизатор GCC так улучшили, что он как раз и сделал то, про что я писал - выкинул кусок кода, в котором было переполнение с int.


Можно по-подробнее? Какой кусок кода выкинули?
Например, в коде:
Используется синтаксис C++
#include <assert.h>

int foo(int a) {
  assert(a+100 > a);
  printf("%d %d\n",a+100,a);
  return a;
}

int main() {
  foo(100);
  foo(0x7fffffff);
}
 

Здесь на некоторых новых версиях gcc, которые слишком строго следуют букве стандарта языка, не срабатывал assert(). Т.к. по стандарту переполнениые знаковых целых - "undefined behavior", оптимизатор выкинул проверку и диагностику, которую проверка должна вызвать. Так вот многие операции с указателями на разные объекты или массивы по стандарту тоже - "undefined behavior", и то, что они сейчас работают - следствие доброты авторов компиляторов. Они пока прощают такое, но т.к. это мешает оптимизатору, могут и закрутить гайки в будущем.

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 60 ]  На страницу Пред.  1, 2, 3, 4  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group