Это зависит от ряда факторов, многие из которых не находятся под вашим контролем. Как упоминал адобриан, в зависимости от ОС у вас есть различные фиксированные верхние пределы, за которыми лежат код ядра и данные. Обычно этот верхний предел составляет не менее 2 ГБ в 32-разрядных ОС; некоторые ОС предоставляют дополнительное адресное пространство. 64-разрядные операционные системы обычно предоставляют верхний предел, контролируемый количеством виртуальных адресных битов, поддерживаемых вашим ЦП (обычно это адресное пространство не менее 40 бит). Однако есть и другие факторы, которые вы не можете контролировать:
- В последней версии linux, сопоставления mmap ниже адрес, настроенный в
/proc/sys/vm/mmap_min_addr
, будет отклонен.
- Вы не можете создавать сопоставления, которые перекрываются с любыми существующими сопоставлениями. Поскольку динамический компоновщик может свободно отображаться в любом месте, которое не пересекается с фиксированными разделами вашего исполняемого файла, это означает, что потенциально любой адрес может быть отклонен.
- Ядро может внедрять другие дополнительные сопоставления, например, системный вызов gate .
malloc
может выполнять mmaps самостоятельно, которые расположены в несколько произвольном месте
Таким образом, нет абсолютно никакой гарантии, что MAP_FIXED
будет успешным, поэтому его обычно следует избегать.
Единственное место, которое я видел, где необходимо MAP_FIXED
, это код запуска Wine, который резервирует (используя MAP_FIXED
) все адреса выше 2G, чтобы избежать путаницы в коде Windows, который предполагает, что сопоставления не будут отображаться. с отрицательным адресом. Это, конечно, узкоспециализированное использование флага.
Если вы пытаетесь сделать это, чтобы избежать необходимости работать со смещениями в разделяемой памяти, один из вариантов будет заключать в класс указатели для автоматической обработки смещений:
template<typename T>
class offset_pointer {
private:
ptrdiff_t offset;
public:
typedef T value_type, *ptr_type;
typedef const T const_type, *const_ptr_type;
offset_ptr(T *p) { set(p); }
offset_ptr() { set(NULL); }
void set(T *p) {
if (p == NULL)
offset = 1;
else
offset = (char *)p - (char *)this;
}
T *get() {
if (offset == 1) return NULL;
return (T*)( (char *)this + offset );
}
const T *get() const { return const_cast<offset_pointer>(this)->get(); }
T &operator*() { return *get(); }
const T &operator*() const { return *get(); }
T *operator->() { return get(); }
const T *operator->() const { return get(); }
operator T*() { return get(); }
operator const T*() const { return get(); }
offset_pointer operator=(T *p) { set(p); return *this; }
offset_pointer operator=(const offset_pointer &other) {
offset = other.offset;
return *this;
}
};
Примечание. Это непроверенный код, но он должен дать вам основную идею.