Влияет ли прямой порядок байтов на массивы?

дана следующая команда на языке C:

unsigned char myID[10] = "123456789"

И учитывая тот факт, что я использую небольшой порядок байтов с архитектурой x86, как это будет сохранено в памяти?

это:

Address     | Value
----------------------
0x10b       | 0x00   ('\0')
0x10a       | 0x00   ('\0')
0x109       | 0x00   ('\0')
0x108       | 0x39   ('9')

0x107       | 0x38   ('8')
0x106       | 0x37   ('7')
0x105       | 0x36   ('6')
0x104       | 0x35   ('5')

0x103       | 0x34   ('4')
0x102       | 0x33   ('3')
0x101       | 0x32   ('2')
0x100       | 0x31   ('1')

или наоборот? Я знаю, что при прямом порядке байтов, заданном 0x0102, младшие байты (02) в этом случае сохраняются в нижней памяти, но я не уверен, что это то же самое для массивов.

Плюс, чтобы сделать умножение на 4, байты добавляются в конец, как я, или наоборот?

Отсутствие порядка байтов влияет только на многобайтовые объекты.

500 - Internal Server Error 13.06.2024 12:52

@500-InternalServerError: Обычно массив представляет собой многобайтовый объект.

Eric Postpischil 13.06.2024 12:53

Учитывая, что myID[x] то же самое, что и *(myID + x), оно должно следовать независимо от порядка байтов машины.

Weather Vane 13.06.2024 13:42

@Дэвид, 0x10b | 0x00 ('\0'), 0x10a | 0x00 ('\0') не уверен, поскольку myID[] имеет только 10 элементов, а не 12.

chux - Reinstate Monica 13.06.2024 14:40

«Плюс, чтобы умножить на 4»… не имеет значения, поскольку размер элемента массива равен 1.

Ian Abbott 13.06.2024 16:02
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
5
165
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Элементы массивов всегда хранятся в памяти в порядке индекса массива. myID[0] находится по самому младшему адресу памяти, myID[1] следует за ним и так далее.

Порядок байтов имеет значение только для скалярных типов, которые являются арифметическими (целочисленные типы и типы с плавающей запятой) и типами указателей. Для типов агрегатов (массивов и структур) элементы или члены агрегата всегда располагаются в порядке их индексов (для массивов) или их объявления (для структур).

Структуры могут иметь внутренние и/или конечные отступы. Массивы не имеют каких-либо дополнений между элементами или после элементов. (Каждый элемент сам по себе может иметь отступы, но это свойство самого элемента, а не массива.)

Отличное объяснение, но я думаю, что пара примеров фактического расположения памяти однобайтового массива элементов (например, пример OP) и многобайтового массива элементов были бы полезны.

Andrey Turkin 13.06.2024 12:58
Ответ принят как подходящий

Элементы массива всегда хранятся в порядке их индексов. Порядок байтов — это то, что влияет на байты в отдельной переменной, которая не является массивом или структурой.

В качестве примера предположим, что у вас есть следующее:

uint16_t arr[4] = { 1, 2, 3, 4 };

На машине с прямым порядком байтов байты массива будут следующими:

---------------------------------------------------------
| 0x01 | 0x00 | 0x02 | 0x00 | 0x03 | 0x00 | 0x04 | 0x00 |
---------------------------------------------------------

На машине с прямым порядком байтов это будет выглядеть так:

---------------------------------------------------------
| 0x00 | 0x01 | 0x00 | 0x02 | 0x00 | 0x03 | 0x00 | 0x04 |
---------------------------------------------------------

Привет, просто чтобы убедиться, что я понимаю, что, если я передам «2024» в int test(char* str), оно будет рассматриваться как массив или нет?

David 13.06.2024 18:42

@David Строковый литерал — это массив, и когда вы передаете его функции, он преобразуется в указатель на его первый элемент.

dbush 13.06.2024 18:49

Спасибо, а где адреса памяти в вашем ответе? и не могли бы вы посмотреть мой комментарий здесь: stackoverflow.com/a/78618174/23344794 думаю, здесь есть большое противоречие.

David 13.06.2024 18:53

@David Адреса в примере расположены в порядке возрастания.

dbush 13.06.2024 18:54

почему это? это противоречие. стек заполняется от более высоких адресов к более низким адресам, поэтому, если 1 является первым элементом, он заполняется в первом свободном месте (по порядку), что означает более высокий адрес...

David 13.06.2024 19:09

@David Существует ли массив в стеке, не имеет значения. Адреса массивов всегда идут от младшего к старшему. Было бы бессмысленно хранить массивы одним способом в стеке, а другим – в куче или в глобальных данных.

dbush 13.06.2024 19:10

Порядок байтов влияет только на представление многобайтовых скалярных типов. Это не влияет на индексацию массива или порядок членов структуры. Ваш массив будет выглядеть одинаково как на архитектуре с прямым порядком байтов, так и с прямым порядком байтов.

Порядок байтов повлияет только на представление отдельных элементов массива или членов структуры.

Данный

struct s { int a; int b; } foo = { 0x01234567, 0x89abcdef };

вы получите что-то вроде этого (адреса только для иллюстрации):

Address    Member    LE    BE
-------    ------    --    --
0x1000          a    67    01
0x1001               45    23
0x1002               23    45
0x1003               01    67
0x1004          b    ef    89
0x1005               cd    ab
0x1006               ab    cd
0x1007               89    ef

не могли бы вы отнестись к моему примеру

David 13.06.2024 18:49

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

David 13.06.2024 18:50

@David - обратите внимание, что стандарт C вообще ничего не говорит о стеках или кучах; это не концепции языка C, а скорее концепции реализации.

ad absurdum 14.06.2024 00:55

@David: члены структуры располагаются в порядке, объявленном с возрастанием адресов, независимо от поведения стека.

John Bode 14.06.2024 09:19

Порядок байтов — это свойство процессора, которое существует, когда набор команд предлагает многобайтовое чтение из памяти и запись в память, например. movq или lw (загрузочное слово).

Поскольку аппаратное обеспечение не поддерживает все возможные размеры, программное обеспечение все равно должно выбирать порядок байтов (или слов/квадратов) в более крупных элементах (например, 12-байтовый или 128-битный тип данных).

Если бы аппаратное обеспечение предлагало чтение и запись в память только в виде байтов, нам пришлось бы выбирать порядок байтов в программном обеспечении — то есть, как составить несколько байтов в слово, двойное, четверное и т. д.

Фактически, программное обеспечение по-прежнему может выбирать порядок байтов, противоположный аппаратному обеспечению, на котором оно работает, и вынуждено это делать, например, при кодировании/декодировании заголовков пакетов TCP/IP на процессоре с прямым порядком байтов (поскольку заголовки TCP/IP используют сетевой порядок байтов, который является прямым порядком байтов). ).  В противном случае для программного обеспечения было бы глупо выбирать порядок байтов, который противоречит тому, что обычно делает оборудование.

Программное обеспечение также выбирает порядок полей в структурах, а для C существуют строгие правила, позволяющие структурам C взаимодействовать с ассемблером и другими языками.

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

Тем не менее, поскольку аппаратное обеспечение, обеспечивающее масштабирование, предлагает только определенные ограниченные размеры, массивы, размер элемента которых не предусмотрен (например, размер элемента 5 или 128), тогда программное обеспечение выполняет масштабирование с использованием умножения и/или сложения (и сдвига и т. д.). .).

Строки — это хранящиеся массивы байтов, в которых каждый последующий элемент (байт/символ) хранится по последовательным (возрастающим) адресам памяти, как и другие массивы, — но поскольку строки представляют собой массивы байтов, не возникает вопроса о порядке байтов или порядка.

Однако если бы вы загрузили 32-битное слово из адреса строки «abcd», числовое значение в 32 битах будет отличаться на процессорах с прямым порядком байтов и с прямым порядком байтов.  Но мы обычно не смотрим на числовые значения размера word/double/quad из строк (мы можем использовать больший размер для копирования строки из одного места в памяти в другое, не обращая внимания на числовые значения).

Привет, просто чтобы убедиться, что я понимаю, что, если я передам «2024» в int test(char* str), оно будет рассматриваться как массив или нет?

David 13.06.2024 18:42

В C почти нет массивов. Массивы — это всего лишь хранилище. Как только вы используете в выражении массив, он сразу преобразуется в указатель, и мы берем его оттуда. Это мгновенное и автоматическое преобразование массива в указатель представляет собой операцию с потерями: как только указатель появляется, язык не знает, на сколько элементов ссылается этот указатель, на один элемент или на несколько. Итак, когда вы пишете test ( "2024" ), «2024» генерирует инициализированный массив байтов в постоянной памяти программы (например, .rodata), а для вызова test компилятор передает адрес первой «2».

Erik Eidt 13.06.2024 19:44

Итак, да, он обрабатывается как любой другой массив в C, то есть он немедленно преобразуется в указатель, и вызываемый здесь test знает только тип элемента, на который ссылается указатель, но не длину, например . Мы могли бы изменить тест следующим образом int test ( char [] str ), но это только предотвращает test от изменения его формального параметра (т.е. str++ сейчас не разрешено), но это не информирует test больше, чем char *str (например, для test до сих пор нет информации о длине массива).

Erik Eidt 13.06.2024 19:46

Другие вопросы по теме