Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 20.12.2013, 02:16   #1
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию Сдвиг указателя на желаемое количиство байт

Доброго дня.
Встроенные операции над указателями жестко привязаны к типу указателя, а как грамотно сдвинуть указатель на произвольное количество байт? Сразу могут прийти варианты:
Код:
int *p = (int*)d;
p = (int*) ((int)p + sizeof(double));        // #1
    
nt *p2 = (int*)d;
p2 = (int*) ((char*)p2 + sizeof(double));    // #2
Но в #1 я привязываюсь к размеру конкретного типа, а размер указателей будет всегда расти и однажды произойдет переполнение. В #2 привязка к размеру другого типа, а везде ли char 1 байт? Для меня это не ясно (насколько мне известно, его размер не более двух байт). Поэтому вопрос: как делать подобную операцию правильно, чтобы не пришлось ее редактировать из-за роста указателей или разных размеров типов на разном оборудовании? В голове крутится мысль о том что возможно для этих целей есть что-то в std. Или какой-то std typedef размер которого будет достаточен для хранения любого адреса.

Последний раз редактировалось 220Volt; 20.12.2013 в 02:19.
220Volt вне форума Ответить с цитированием
Старый 20.12.2013, 08:46   #2
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,331
По умолчанию

Ну если подходить так строго, то никак - размер char не определен, но его можно узнать из CHAR_BIT. Раз так уж важно, можете сделать так:
((char*) ptr) + (sizeof(double) / sizeof(char))

Второй вариант, вынести все это в функцию, которая может быть имплементирована по разному на разных архитектурах.

Я думаю надо будет очень постараться, чтоб найти С компилятор и/или архитектуру, где char != 8 бит

Массив - не всегда самый удачный способ хранения данных. Сделайте массив указателей а указатель может быть на любого наследника. Даже в базах данных таблицы содержат "одинаковые" структуры.
waleri вне форума Ответить с цитированием
Старый 20.12.2013, 13:31   #3
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

Спасибо.
Я покопался в справочнике вот что нашел http://www.cplusplus.com/reference/cstdint/:
Код:
intptr_t uintptr_t Integer type capable of holding a value converted from a void pointer and then be converted back to that type with a value that compares equal to the original pointer.
Optional: These typedefs may not be defined in some library implementations.*
Поэтому на мой взгляд вполне верным и безопасным является вариант:
Код:
#include <iostream>
#include <cstdint>

using namespace std;

    
int main()
{
    double d[2];
    
    int *p = (int*)d;
    p = (int*) ((uintptr_t)p + sizeof(double)); 
    
    cout << &d[1] << "\n" << p;
    
    return 0;
}
220Volt вне форума Ответить с цитированием
Старый 20.12.2013, 13:52   #4
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

Цитата:
Сообщение от waleri Посмотреть сообщение
... Раз так уж важно, можете сделать так:
((char*) ptr) + (sizeof(double) / sizeof(char))

...
Пользовательский тип ведь необязательно кратен двум, например:
Код:
struct S
{
    char ar[9];
};
220Volt вне форума Ответить с цитированием
Старый 20.12.2013, 13:57   #5
ROD
Linux C++ Qt ARM
Старожил
 
Аватар для ROD
 
Регистрация: 30.11.2008
Сообщений: 3,030
По умолчанию

<тут было что-то страшное>
Дилетант широкого профиля.

"Слова ничего не стоят - покажите мне код!" © Линус Торвальдс

Последний раз редактировалось ROD; 20.12.2013 в 14:08.
ROD вне форума Ответить с цитированием
Старый 20.12.2013, 15:53   #6
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

А зачем это нужно?
Недавно заводил тему http://www.programmersforum.ru/showthread.php?t=251137.
Так вот такое решение у меня получилось:
Код:
#include <iostream>
#include <cstdint>
#include <type_traits>

using namespace std;

template <typename _Ty>
    class Array_wrapper
    {
        _Ty *array;
        size_t el_size;
    public:
        template <typename _Ar_Ty>
            Array_wrapper(_Ar_Ty *array)
            {
                static_assert(is_base_of<_Ty, _Ar_Ty>::value, "_Ar_Ty is not derived from _Ty");

                this->el_size = sizeof(_Ar_Ty);
                this->array = array;
            }
            
        _Ty &operator[](size_t index)const
        {
            return *(_Ty*) ((uintptr_t)this->array + this->el_size * index);
        }
    };

struct S                
{ 
    int t; 
};

struct S2 : public S    
{ 
    int q;
};

void f(const Array_wrapper<S> &ps, int size)
{
    for(int i = 0;  i < size;  ++ i)
        cout << ps[i].t << "\n";
}

int main()
{
    constexpr int size = 5;
    S2 ar[size];
    
    for(int i = 0;  i < size;  ++ i)
        ar[i].t = ar[i].q = i;
    
    f(Array_wrapper<S> {ar}, size);
    
    return 0;
}
Теперь все работает правильно, мне нравится. Допускаю что возможно я плохо знаю std и что-то подобное там уже есть. Думаю не всегда удобно сделать функцию f() шаблонной и подобный трюк может помочь.
Вложения
Тип файла: zip source.zip (700 байт, 18 просмотров)

Последний раз редактировалось 220Volt; 21.12.2013 в 01:02. Причина: Добавил static_assert
220Volt вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Функция изменяет старший байт числа на заданное значение,не изменяя младший байт ( C++ ) Любимый_1 Помощь студентам 3 07.10.2013 16:42
Копирование указателя С++ Alex1991 Помощь студентам 2 24.04.2011 04:00
c++ возврат указателя из функции Neolit1819 Помощь студентам 6 28.03.2011 15:37
Найти байт максимальным количестов единиц и байт с максмальным количеством нулей и разность (ассемблер) Beren42 Помощь студентам 0 15.12.2010 20:32