Если я хочу безопасно кодировать на Rust, должен ли я кодировать без использования арифметики указателей?

Я читал, что арифметика указателей в Rust может выполняться через функцию pointer.offset(), но ее всегда нужно реализовывать в unsafe code:

fn main() {
    let buf: [u32; 5] = [1, 2, 3, 4, 5];
    let mut ptr1: *const u32 = buf.as_ptr();
    unsafe {
        let ptr2: *const u32 = buf.as_ptr().offset(buf.len() as isize);
        while ptr1 < ptr2 {
            println!("Address {:?} | Value {}", ptr1, *ptr1);
            ptr1 = ptr1.offset(1);
        }
    }
}

Если я хочу безопасно кодировать на Rust, должен ли я кодировать без использования арифметики указателей и просто используя, например, соответствующий индекс массива? Или есть другой способ?


person Habebit    schedule 09.04.2019    source источник
comment
Вопрос довольно расплывчатый. Если вы просто хотите выполнить итерацию по массиву, вам следует использовать for reference_to_u32 in buf.iter(), и вы должны использовать небезопасный код только в том случае, если у вас есть для этого причина. Существует бесконечное множество причин, почему вы можете захотеть использовать арифметику указателей, и в некоторых случаях использование pointer.offset() является правильным инструментом, но без какой-либо более конкретной информации мы не можем ответить на этот вопрос.   -  person Sven Marnach    schedule 09.04.2019
comment
Если у вас нет веских и конкретных причин для работы с арифметикой указателей, я предлагаю вместо OP написать более идиоматический код. Игровая площадка . Если вы хотите работать с арифметикой указателя, то это гарантируется только самим разработчиком, это считается небезопасным, и поэтому вам нужно написать его в небезопасном блоке.   -  person Akiner Alkan    schedule 09.04.2019
comment
TL;DR: Просто не надо.   -  person Jan Nils Ferner    schedule 09.04.2019


Ответы (2)


Если я хочу безопасно кодировать на Rust

Тогда вам не следует использовать unsafe. Есть несколько законных причин для unsafe (например, доступ к ячейкам памяти, которые известны и безопасны для использования, например, на микроконтроллерах несколько регистров), но, как правило, вы не должны его использовать.

должен ли я кодировать, не используя арифметику указателя и просто используя соответствующий индекс массива, например

Да. Нет причин (в данном конкретном случае) вообще использовать unsafe. Просто используйте

for i in 0..buf.len() {
    println!("Value {}", buf[i]);
}

Однако этот код не считается «ржавым», вместо этого используйте цикл for

for i in &buf {
    println!("Value {}", i);
}
person hellow    schedule 09.04.2019
comment
Тогда вам не следует использовать unsafe — хотя я согласен с общей темой этого ответа, говорить никогда не использовать unsafe — не лучший вариант. Бывают случаи, когда требуется небезопасный код (помимо приведенных вами примеров). Написать unsafe код правильно очень сложно, и его, конечно же, следует избегать, насколько это возможно. - person Shepmaster; 10.04.2019

Использование таких необработанных указателей вряд ли[1] будет быстрее, чем идиоматический цикл for над итератором:

fn main() {
    let buf: [u32; 5] = [1, 2, 3, 4, 5];
    for val in buf.iter() {
        println!("Address {:?} | Value {}", val as *const u32, val);
    }
}

Это также намного легче читать и не создает рисков небезопасности памяти.


1 На самом деле ваш код сравнивает два значения указателя на каждой итерации, поэтому он, вероятно, будет намного медленнее, чем идиоматический цикл for, который часто может пропустить все проверки границ.

person Peter Hall    schedule 09.04.2019