Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / C++ Новый топик    Ответить
 преобразование массива к unsigned long  [new]
andron81
Member

Откуда: Смоленск
Сообщений: 1106
Добрый вечер.

А может кто-нибудь пояснить , что физически представляет собой преобразование массива из байтов в unsigned long ?

unsigned char pool[3];
    for (int i = 0; i < 3; i++)
        pool[i] = 0;
    unsigned long X = (unsigned long)pool;


в результате X = 2030976 почему получается это число ???
2 май 21, 23:01    [22317653]     Ответить | Цитировать Сообщить модератору
 Re: преобразование массива к unsigned long  [new]
petrav
Member

Откуда:
Сообщений: 2944
andron81,

Это не преобразование массива. Это преобразование адреса массива к unsigned long. Т.е. в unsigned long сохранился адрес массива в оперативной памяти. В данном случае адрес массива равен адресу нулевого элемента этого массива.
2 май 21, 23:06    [22317655]     Ответить | Цитировать Сообщить модератору
 Re: преобразование массива к unsigned long  [new]
andron81
Member

Откуда: Смоленск
Сообщений: 1106
petrav
andron81,

Это не преобразование массива. Это преобразование адреса массива к unsigned long. Т.е. в unsigned long сохранился адрес массива в оперативной памяти. В данном случае адрес массива равен адресу нулевого элемента этого массива.


спасибо.
2 май 21, 23:12    [22317661]     Ответить | Цитировать Сообщить модератору
 Re: преобразование массива к unsigned long  [new]
andron81
Member

Откуда: Смоленск
Сообщений: 1106
petrav
andron81,

Это не преобразование массива. Это преобразование адреса массива к unsigned long.


точно, pool ведь содержит адрес первого элемента массива. тупанул.

Сообщение было отредактировано: 2 май 21, 23:13
2 май 21, 23:19    [22317664]     Ответить | Цитировать Сообщить модератору
 Re: преобразование массива к unsigned long  [new]
petrav
Member

Откуда:
Сообщений: 2944
andron81
petrav
andron81,

Это не преобразование массива. Это преобразование адреса массива к unsigned long.


точно, pool ведь содержит адрес первого элемента массива. тупанул.

Нулевого элемента массива. И нет такой переменной pool, которая содержала бы адрес чего-то.
2 май 21, 23:26    [22317665]     Ответить | Цитировать Сообщить модератору
 Re: преобразование массива к unsigned long  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6658
andron81,

Для справки, если у вас есть массив байтов которые вы хотите рассматривать как другой тип, то единственный способ это сделать без UB это memcpy() в отдельную переменную этого типа.
Работать же напрямую, через преобразование типа - это UB.

unsigned char pool[sizeof(long)] = {...};

long l;
memcpy(&l, pool, sizeof(l)); // OK

l = *(long*)pool; // UB
3 май 21, 11:13    [22317725]     Ответить | Цитировать Сообщить модератору
 Re: преобразование массива к unsigned long  [new]
andron81
Member

Откуда: Смоленск
Сообщений: 1106
Anatoly Moskovsky
andron81,

Для справки, если у вас есть массив байтов которые вы хотите рассматривать как другой тип, то единственный способ это сделать без UB это memcpy() в отдельную переменную этого типа.
Работать же напрямую, через преобразование типа - это UB.

unsigned char pool[sizeof(long)] = {...};

long l;
memcpy(&l, pool, sizeof(l)); // OK

l = *(long*)pool; // UB


ого. да я смотрю вообще все эти преобразования это надо 20 раз подумать прежде чем делать. я почему спрашиваю в книге Эккеля разбирается перегрузка new и delete для классов. очень подробно разжовывать эккель не любит что делает в своих примера поэтому приходится догадываться. в общем как я понимаю он тут велосипедит new при помощи массива и держит массив с состоянием занят/не занят блок . а потом делает delete и вычисляет координату блока и помечает её как свободная. так вот там как раз это преобразование. Вы хотите сказать, что тут UB в delete ?


#include <cstddef> // Size_t
#include <fstream>
#include <iostream>
#include <new>
using namespace std;
ofstream out("Framis.out");

class Framis {
    enum { sz = 10 };
    char c[sz]; // To take up space, not used
    static unsigned char pool[];
    static bool alloc_map[];
public:
    enum { psize = 100 };  // frami allowed
    Framis() { out << "Framis()\n"; }
    ~Framis() { out << "~Framis() ... "; }
    void* operator new(size_t u) throw(bad_alloc);
    void operator delete(void*);
};
unsigned char Framis::pool[psize * sizeof(Framis)];
bool Framis::alloc_map[psize] = { false };

// Size is ignored -- assume a Framis object
void*
Framis::operator new(size_t u) throw(bad_alloc) {
    for (int i = 0; i < psize; i++)
        if (!alloc_map[i]) {
            out << "using block " << i << " ... ";
            alloc_map[i] = true; // Mark it used
            return pool + (i * sizeof(Framis));
        }
    out << "out of memory" << endl;
    throw bad_alloc();
}

void Framis::operator delete(void* m) {
    if (!m) return; // Check for null pointer
    // Assume it was created in the pool
    // Calculate which block number it is:
    unsigned long block = (unsigned long)m
        - (unsigned long)pool;
    block /= sizeof(Framis);
    out << "freeing block " << block << endl;
    // Mark it free:
    alloc_map[block] = false;
}

int main() {
    Framis* f[Framis::psize];
    try {
        for (int i = 0; i < Framis::psize; i++)
            f[i] = new Framis;
        new Framis; // Out of memory
    }
    catch (bad_alloc) {
        cerr << "Out of memory!" << endl;
    }
    delete f[10];
    f[10] = 0;
    // Use released memory:
    Framis* x = new Framis;
    delete x;
    for (int j = 0; j < Framis::psize; j++)
        delete f[j]; // Delete f[10] OK
} ///:~
3 май 21, 13:16    [22317764]     Ответить | Цитировать Сообщить модератору
 Re: преобразование массива к unsigned long  [new]
Dima T
Member

Откуда:
Сообщений: 15795
Anatoly Moskovsky
единственный способ это сделать без UB это memcpy()

А как же union ?
union {
  unsigned char pool[sizeof(long)];
  long l;
} pl;

for(size_t i = 0; i != sizeof(long); i++) p.pool[i] = 0;
printf("%u\n", pl.l);
3 май 21, 13:19    [22317765]     Ответить | Цитировать Сообщить модератору
 Re: преобразование массива к unsigned long  [new]
petrav
Member

Откуда:
Сообщений: 2944
Dima T
Anatoly Moskovsky
единственный способ это сделать без UB это memcpy()

А как же union ?
union {
  unsigned char pool[sizeof(long)];
  long l;
} pl;

for(size_t i = 0; i != sizeof(long); i++) p.pool[i] = 0;
printf("%u\n", pl.l);

Там тоже UB, как я понимаю. С++ такой язык — что не сделай UB. И выход один: пиши свой класс строк, потому что все этим занимаются.
3 май 21, 13:22    [22317767]     Ответить | Цитировать Сообщить модератору
 Re: преобразование массива к unsigned long  [new]
Dima T
Member

Откуда:
Сообщений: 15795
petrav
Там тоже UB, как я понимаю. С++ такой язык — что не сделай UB.

memcpy(), union и прочие вышеописанные попытки подменить один тип данных другим это не совсем UB, но работает только для POD типов.
3 май 21, 13:27    [22317771]     Ответить | Цитировать Сообщить модератору
 Re: преобразование массива к unsigned long  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 53394

Dima T
А как же union ?

Это UB в С++, но нормально в С. Поэтому компиляторы обычно молча применяют С-поведение,
даже если исходник на С++.

Posted via ActualForum NNTP Server 1.5

3 май 21, 13:29    [22317774]     Ответить | Цитировать Сообщить модератору
 Re: преобразование массива к unsigned long  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6658
Dima T
А как же union ?

Если можно pool обернуть в union, то да. Но не всегда возможно.
petrav
Там тоже UB, как я понимаю.

Нет. С union нет UB если массив байтов содержит валидный объект который trivially-copyable (как в данном примере).

Dima T
memcpy(), union и прочие вышеописанные попытки подменить один тип данных другим это не совсем UB, но работает только для POD типов.

Для не POD по-моему должно быть и так очевидно, что создавать объект побайтно нельзя.
А для POD основная проблема которую решают memcpy и union это выравнивание.
Есть платформы где нельзя в произвольном месте читать long и прочие типы. Поэтому UB если char* приводится к long* и разыменовывается, если там не было объекта такого типа.

Но например так можно даже и для не POD:
std::string s;
char* p = (char*)&s;
*(std::string*)p = "xxx"; // можно потому что известно что p указывает на объект типа std::string
3 май 21, 13:44    [22317782]     Ответить | Цитировать Сообщить модератору
 Re: преобразование массива к unsigned long  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 53394

Anatoly Moskovsky
С union нет UB если массив байтов содержит валидный объект который trivially-copyable (как
в данном примере).

Это они одумались только в 14-м стандарте.
https://en.cppreference.com/w/cpp/language/union
The details of that allocation are implementation-defined but all non-static data
members will have the same address (since C++14). It's undefined behavior to read from the
member of the union that wasn't most recently written. Many compilers implement, as a
non-standard language extension, the ability to read inactive members of a union.

Posted via ActualForum NNTP Server 1.5

3 май 21, 13:54    [22317787]     Ответить | Цитировать Сообщить модератору
 Re: преобразование массива к unsigned long  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6658
Dimitry Sibiryakov
Это они одумались только в 14-м стандарте.

Ну, формально да.
Но на практике я думаю что нет и никогда не было компиляторов которые бы не поддерживали алиасинг через union.
Т.е. это стандарт дефакто.

А вот reinterpret_cast (и c-cast) реально на некоторых платформах не работают.
3 май 21, 14:59    [22317835]     Ответить | Цитировать Сообщить модератору
 Re: преобразование массива к unsigned long  [new]
a guest
Member

Откуда:
Сообщений: 335
Anatoly Moskovsky
Для справки, если у вас есть массив байтов которые вы хотите рассматривать как другой тип, то единственный способ это сделать без UB это memcpy()
Единственный способ это std::bit_cast, а memcpy между объектами разных типов это UB.
4 май 21, 10:39    [22318145]     Ответить | Цитировать Сообщить модератору
 Re: преобразование массива к unsigned long  [new]
a guest
Member

Откуда:
Сообщений: 335
Anatoly Moskovsky
Для не POD по-моему должно быть и так очевидно, что создавать объект побайтно нельзя.
Что такое "создавать объекты побайтно"?
4 май 21, 10:43    [22318146]     Ответить | Цитировать Сообщить модератору
 Re: преобразование массива к unsigned long  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6658
a guest
Единственный способ это std::bit_cast, а memcpy между объектами разных типов это UB.

Нет.
4 май 21, 11:28    [22318161]     Ответить | Цитировать Сообщить модератору
 Re: преобразование массива к unsigned long  [new]
a guest
Member

Откуда:
Сообщений: 335
Anatoly Moskovsky
a guest
Единственный способ это std::bit_cast, а memcpy между объектами разных типов это UB.

Нет.
Ок, UB между объектами разных типов, за исключением описанного в http://eel.is/c draft/basic.types.general#2
4 май 21, 13:31    [22318256]     Ответить | Цитировать Сообщить модератору
Все форумы / C++ Ответить