Какова разница в скорости между индексами и указателями?

Как можно улучшить производительность операции присваивания элементам массива c в зависимости от значений элементов массивов a и b? Есть ли разница в скорости между обращением к элементам массивов через индексы и обращением через указатели? Я провел некоторые тесты на моем компьютере, но мне нужны рекомендации на основе более объективных данных.
  • 3 января 2024 г. 10:51
Ответы на вопрос 2
В контексте языков программирования C и C++, разница в скорости между обращением к элементам массива через индексы и через указатели обычно минимальна или отсутствует. Это потому, что при оптимизации компилятор преобразует индексацию массива в операции, аналогичные тем, что используются при работе с указателями.

Тем не менее, если вы работаете с оптимизацией на очень низком уровне, вам важно понимать, как компилятор преобразует обращение к массиву через индексы и как это сравнивается с доступом через указатели.

Доступ к элементам массива через индексы, как правило, реализуется как операция со смещением относительно начала массива:

```c
int value = array[index];
```

Это преобразуется в нечто вроде:

```assembly
MOV EAX, [EBP + index*4 + offset_of_array]
```

Тогда как работа с указателями происходит напрямую:

```c
int value = *(ptr + index);
```

Это может быть представлено аналогичной инструкцией ассемблера:

```assembly
MOV EAX, [ECX + index*4]
```

Если вы хотите улучшить производительность операции присваивания элементам массива `c` в зависимости от значений элементов массивов `a` и `b`, вот некоторые общие рекомендации:

1. Использование оптимизирующих компиляторов: Современные компиляторы (например, GCC или Clang) могут автоматически оптимизировать код так, чтобы использовать наиболее эффективные инструкции для доступа к массивам.

2. Локализация данных: Обеспечение локализации данных и их последовательности в памяти может уменьшить кэш-промахи и улучшить производительность.

3. Уменьшение количества операций: Минимизация операций внутри циклов, особенно если они могут быть выполнены за пределами цикла.

4. Использование оптимизации циклов: Луп анроллинг (разворачивание циклов) и иные трансформации, которые уменьшают накладные расходы на итерации цикла и позволяют компилятору лучше использовать инструкции SIMD, где это возможно.

5. Параллелизм: Использование потоков или векторизация с помощью инструкций SIMD может ускорить обработку данных, особенно для больших массивов.

6. Избегание условий в горячих путях: Условные переходы внутри циклов могут приводить к плохой предсказуемости ветвлений и замедлять выполнение. Часто лучше структурировать код так, чтобы минимизировать количество условий внутри циклов.

Определенный выбор оптимизации будет во многом зависеть от конкретных требований вашей задачи, архитектуры процессора, компилятора, и может потребовать профилирования и тестирования кода. Для получения более точных рекомендаций по оптимизации, необходимо изучить генерируемый ассемблер
Зависит от модели процессора, версии и опций компилятора и немножечко фазы луны. В целом без разницы. <br/> <br/> Практический совет - лучше писать через индексы, ибо так понятнее и больше шансов что компилятор там все наоптимизирует (например, он сможет векторизовать работу через какие-нибудь SSE инструкции процессора). <br/> <br/> Совет по бенчмарку - если памяти не хватает, стоит по одному достаточно большому массиву пройтись 10000 раз. А лучше использовать готовые фреймворки для измерения скорости, вроде того де gbenchmark. <br/> <br/> Еще, иногда полезно посмотреть на ассемблерный выхлоп. <a href="https://godbolt.org/#z:OYLghAFBqd5TKALEBjA9gEwKYFFMCWALugE4A0BIEAZgQDbYB2AhgLbYgDkAjF%2BTXRMiAZVQtGIHgBYBQogFUAztgAKAD24AGfgCsp5eiyahUAUgBMAIUtXyKxqiIEh1ZpgDC6egFc2TKQBWcncAGQImbAA5PwAjbFIpC3IAB3QlYhcmL19/INT0zKFwyJi2eMSeZIdsJyyRIhZSIhy/AJ5gmrqhBqaiEui4hKT7RubWvI7RvoGyiqSASnt0H1JUTi5LAGYI1F8cAGozLY9UJSJMHBpj3DMtAEE7x4stq4jsA6iDni0np4iiAcvGwUj4iNgeBAAQcWGZAlYonCACLkA7Q2JwhHIhZHADsNgeByJaOEB3M8MRgSRxwJ92JJMBSj8Ry2SIOvy2tPpglIBwgGQAXtgAPqAggstkcqxolkeT40o7WWwEHFmfFPen08lWAjIiV8jHw3VUiXHSWqrYAMQOhp1epAfNhRr1AHobZjjUiFjSNZqiUy2IqbKyyR7kT7CcS1dTI0TSNgiKsmAcAxHHrikVwlvRuIF%2BAEuDpyOhuB5bLYUys1h9tnxyERtFmlgBrECBLSGbjSfhsNsdgtFktcfhKEAdhuFrPkOCwFAYHD4YhkSjUOiMVgcbh1wTCMQSTgyOTCZRqTST8j6ZJGExocvWezYRzOVwQdwTALSXEhJiYWZDSo8AUGTPtk3htCAn5AUUTB/uUww8IBXQgb04xgXkkFIfUYz9O8czwYh2HvhBX7nDMuH/lIPBLEoVbrNw2y7PsNYnAAbrUJCkDcfwPNsbyRJ83y/DxDzQsCoLghYUKkk6WJUqi6KYpSXp4lyxLQtqSlpvSAIAFRokQwosPqsKcr6RK6fpwqxPqGKmbGDIpsyZrslpxI8o6YLoJYABslmoAcDqoKq6r2dpBn%2Bc5EA6cQVmmiGWgWta0UGdZDpRTFRluslVnenZdJ%2BkGyoGSZql%2BneOopa5foBoVIYxeYeX0tGZkHPGiakMmqZ5dGU45lwebkAO/BDmWSrWJWqzrIqWwWPwE46AsSxINgLA4IkEDZl2PZ9oNjbFtwI5jvWjaLeQrbSIEAB03kAJw8DdWjeVoWiBBYFj3VsnZcFs%2BZ7UOc0ndOiAQHO6AggwCQrhAGDg4wiR7MYwA8FsWiAWu4KkKOECxHtsQRE0ACeW78HjrCkATADysS6OxxPkDDHDCBTTD0ET544LEPjAB4Ej0KOvD8DgbCI5I7MEPGdRsfzRbYOotRghsdYAo%2Be30AQsSkITXg4HtRCkAQvYC0sNBGMASgAGoENgADuFMpMwdM7qI4iSIeTsnhoe36IB16mOVhjq6OkBLOgKQgfzAC0FM/cWbGkPrOBBxtD5Plkbg/kRgFhORcGVFBIGZ/nWSwfMiGPuxWF9IXmE9NhJfwdMqG5O0jc4aUFFUcsk0Hpt/W/eeQ4HOoAAc3kR950hkr73xbJdWiXTwfKLhx01UQDk5LCDaBgykEMUFQ0M73vaC%2B8jqMCAwGNYzj56k4TdN3%2BTVM004dMM8wRDM6ze0c1zPP0HzOmQsRYbCLIQCWzgpZ7VlvLcEdNlZ9SLGrDWWssCgLmvrQ2fBjamwtlbW29sCzbnkHuV2sh3YqE9ueS8hhEa3jGnYZBScQ5hyyJHaOw044J2wMwlOFcXxvjQi3bO7dc4GDSMBLIhcJHQXrnnGuTAUItCEQYBRSi5GqMIiogiZFRGl2orRTgFhe4DSGvtLgQ9R7j0ngjEwM854LyXoQFe2xjHrwWtOFAhAaA0Chk7UhB5yHyA9meJBSBRw%2B3Cd4mgRACb2yOvQcJss9YsFDiBA65BSDhJAMkLJShomxPiR2PJyTNZpLTsOEx/dBzcCRAQHxBxLY2wSJYseE8p6I3sfPReLElCtOsR0uxyMHF1nmk2cgy1VrDGTq2QI0hLoo2HloG6Wwbo3U/LiJZuJvJfW7OQXsPx%2Bx/QyaOZIYzTp9VmrtAeGTzlLDjhkVw0ggA%3D" rel="nofollow">Вот</a> , например, что происходит при -O3 опции компилятора. Он генерирует вообще идентичный код для обеих функций (развернув циклы)! И даже при -O2 оно одинаковый код выдает. <br/> <br/> Без оптимизаций код <a href="https://godbolt.org/#z:OYLghAFBqd5TKALEBjA9gEwKYFFMCWALugE4A0BIEAZgQDbYB2AhgLbYgDkAjF%2BTXRMiAZVQtGIHgBYBQogFUAztgAKAD24AGfgCsp5eiyahUAUgBMAIUtXyKxqiIEh1ZpgDC6egFc2TKQBWcncAGQImbAA5PwAjbFIpC3IAB3QlYhcmL19/INT0zKFwyJi2eMSeZIdsJyyRIhZSIhy/AJ5gmrqhBqaiEui4hKT7RubWvI7RvoGyiqSASnt0H1JUTi5LAGYI1F8cAGozLY9UJSJMHBpj3DMtAEE7x4stq4jsA6iDni0np4iiAcvGwUj4iNgeBAAQcWGZAlYonCACLkA7Q2JwhHIhZHADsNgeByJaOEB3M8MRgSRxwJ92JJMBSj8Ry2SIOvy2tPpglIBwgGQAXtgAPqAggstkcqxolkeT40o7WWwEHFmfFPen08lWAjIiV8jHw3VUiXHSWqrYAMQOhp1epAfNhRr1AHobZjjUiFjSNZqiUy2IqbKyyR7kT7CcS1dTI0TSNgiKsmAcAxHHrikVwlvRuIF%2BAEuDpyOhuB5bLYUys1h9tnxyERtFmlgBrECBLSGbjSfhsNsdgtFktcfhKEAdhuFrPkOCwFAYHD4YhkSjUOiMVgcbh1wTCMQSTgyOTCZRqTST8j6ZJGExocvWezYRzOVwQdwTdpbEJMTCzIaJYJpBkz7ZN4bRSJ%2BgFFEwv7lMMnSPrUwG9OMoGTJ%2BXRIWM/TvHMcHTChuQfvh2GlH%2BbZLEoVbrNw2y7PsNYnAAbohZA3H8DzbG8kSfN8vwcQ80LAqC4IWFCpJOliVKouimKUl6eJcsS0LanJab0gCABUaJEMKLD6rCnK%2BkSmnacKsT6hihmxgyKbMma7JqcSPKOmC6CWAAbKZqAHA6qCquq1nqTp3n2RAGnEGZpohloFrWuFOnmQ6YURXpbrxWZ3pWXSfpBsqOkGYpfp3jqCWOX6Aa5SGEXmFl9LRkZBzxompDJqmWXRlOOZcHm5ADvwQ5lkq1iVqs6yKlsFj8BOOgLEsSDYCwOCJBA2Zdj2fa9Y2xbcCOY71o2s3kK20iBAAdO5ACcPAXVo7laFogQWBY12fl1Wz5ltQ5TQd06IBAc7oCCDAJCuEAYEDjCJHsxjADwWxaDwAgMOCpCjhAsRbbEERNAAnlu/BY6wpA4wA8rEuiIfj5Dgxwwgk0w9B4%2BeOCxD4wAeBI9Cjrw/A4GwMOSMzBDxnUzHc0W2DqLUYIbHWAKPlt9AELEpC414OBbUQpAEL2PNLDQRjAEoABqBDYAA7iTKTMFTO6iOIkiHnbJ4aFt%2BiI9epjFYYyujpASzoCkwHcwAtCTg7MaQ2s4H7K0Pk%2BWRuN%2B74GGEOFkYjkHASnmeFMBMHzIjGH1FhOfx4hJczOnsGVMRZfnFXpE11IFFUQeq3dR955Dgc6gABzuSH7nSGSnvfFsp1aKdPB8ouJC8rWCzfZOSz/WggMpMDFBUGDG9b2gntwwjSP0CjaMY%2BehO41TV/E2TFNOFTNPMEQ9OM1tLNsxz9Bc1TfMCxsIshARbODFltSW0twRU3ll1IsSsVZqywIAqa2tdZ8H1obE2ZtLbWwLNueQe5HayGdioV255LyGBhreIadh4GxwDkHLIodw79UjtHbA9Dy7dACK%2BZOqF2hfh/NXQuBQgJZDLlnLIBdhhFwQtw5CLR%2BEGGLj0LC0ja4NwImBIuajhEyNbqNTgFgO49T6ttLgvcB5DxHtDEw49J7T1noQee41jHLxmtOFAhAaA0FBnbQhB5iHyBdmeOBSBRwe3Cd4mgRAcbWz2vQcJkstYsEDsBHa5BSDhJAMkLJShomxPiR2PJyTVZpMTsOExXdBzcCRAQHxBxTYWwSJYwew9R4w3sVPGejElCtOsR0uxcMHF1mmk2cg81FrDDjq2QI0hTrwz7loC6WwLoXWkLiXESzcTuU7Fwbs5Bew/H7J9DJo5khjMOl1Sam1u4ZMuUsSOGRXDSCAA%3D" rel="nofollow">разный</a> , но в там все не так как вы думаете. Вместо инструкции <code>mov eax, dword ptr [rax + 4*rcx]</code> в варианте с индексами используется инструкция <code>mov eax, dword ptr [rax]</code> для указателей. Это самое "складывание с указателем массива" вообще не отдельная операция - а вариант адрессации в инструкции mov. Они могут вообще одинаковое количество тактов занимать, это надо мануал по конкретной архитектуре процессоров читать.
Похожие вопросы