дана следующая команда на языке 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-InternalServerError: Обычно массив представляет собой многобайтовый объект.
Учитывая, что myID[x]
то же самое, что и *(myID + x)
, оно должно следовать независимо от порядка байтов машины.
@Дэвид, 0x10b | 0x00 ('\0')
, 0x10a | 0x00 ('\0')
не уверен, поскольку myID[]
имеет только 10 элементов, а не 12.
«Плюс, чтобы умножить на 4»… не имеет значения, поскольку размер элемента массива равен 1.
Элементы массивов всегда хранятся в памяти в порядке индекса массива. myID[0]
находится по самому младшему адресу памяти, myID[1]
следует за ним и так далее.
Порядок байтов имеет значение только для скалярных типов, которые являются арифметическими (целочисленные типы и типы с плавающей запятой) и типами указателей. Для типов агрегатов (массивов и структур) элементы или члены агрегата всегда располагаются в порядке их индексов (для массивов) или их объявления (для структур).
Структуры могут иметь внутренние и/или конечные отступы. Массивы не имеют каких-либо дополнений между элементами или после элементов. (Каждый элемент сам по себе может иметь отступы, но это свойство самого элемента, а не массива.)
Отличное объяснение, но я думаю, что пара примеров фактического расположения памяти однобайтового массива элементов (например, пример OP) и многобайтового массива элементов были бы полезны.
Элементы массива всегда хранятся в порядке их индексов. Порядок байтов — это то, что влияет на байты в отдельной переменной, которая не является массивом или структурой.
В качестве примера предположим, что у вас есть следующее:
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 Строковый литерал — это массив, и когда вы передаете его функции, он преобразуется в указатель на его первый элемент.
Спасибо, а где адреса памяти в вашем ответе? и не могли бы вы посмотреть мой комментарий здесь: stackoverflow.com/a/78618174/23344794 думаю, здесь есть большое противоречие.
@David Адреса в примере расположены в порядке возрастания.
почему это? это противоречие. стек заполняется от более высоких адресов к более низким адресам, поэтому, если 1 является первым элементом, он заполняется в первом свободном месте (по порядку), что означает более высокий адрес...
@David Существует ли массив в стеке, не имеет значения. Адреса массивов всегда идут от младшего к старшему. Было бы бессмысленно хранить массивы одним способом в стеке, а другим – в куче или в глобальных данных.
Порядок байтов влияет только на представление многобайтовых скалярных типов. Это не влияет на индексацию массива или порядок членов структуры. Ваш массив будет выглядеть одинаково как на архитектуре с прямым порядком байтов, так и с прямым порядком байтов.
Порядок байтов повлияет только на представление отдельных элементов массива или членов структуры.
Данный
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 - обратите внимание, что стандарт C вообще ничего не говорит о стеках или кучах; это не концепции языка C, а скорее концепции реализации.
@David: члены структуры располагаются в порядке, объявленном с возрастанием адресов, независимо от поведения стека.
Порядок байтов — это свойство процессора, которое существует, когда набор команд предлагает многобайтовое чтение из памяти и запись в память, например. movq или lw (загрузочное слово).
Поскольку аппаратное обеспечение не поддерживает все возможные размеры, программное обеспечение все равно должно выбирать порядок байтов (или слов/квадратов) в более крупных элементах (например, 12-байтовый или 128-битный тип данных).
Если бы аппаратное обеспечение предлагало чтение и запись в память только в виде байтов, нам пришлось бы выбирать порядок байтов в программном обеспечении — то есть, как составить несколько байтов в слово, двойное, четверное и т. д.
Фактически, программное обеспечение по-прежнему может выбирать порядок байтов, противоположный аппаратному обеспечению, на котором оно работает, и вынуждено это делать, например, при кодировании/декодировании заголовков пакетов TCP/IP на процессоре с прямым порядком байтов (поскольку заголовки TCP/IP используют сетевой порядок байтов, который является прямым порядком байтов). ). В противном случае для программного обеспечения было бы глупо выбирать порядок байтов, который противоречит тому, что обычно делает оборудование.
Программное обеспечение также выбирает порядок полей в структурах, а для C существуют строгие правила, позволяющие структурам C взаимодействовать с ассемблером и другими языками.
Хотя также можно было бы хранить элементы массива в памяти задом наперед или в каком-либо другом порядке, очевидный выбор увеличения индекса означает, что увеличение адреса памяти является простым и часто поддерживается набором команд с режимами индексации и масштабирования адресации.
Тем не менее, поскольку аппаратное обеспечение, обеспечивающее масштабирование, предлагает только определенные ограниченные размеры, массивы, размер элемента которых не предусмотрен (например, размер элемента 5 или 128), тогда программное обеспечение выполняет масштабирование с использованием умножения и/или сложения (и сдвига и т. д.). .).
Строки — это хранящиеся массивы байтов, в которых каждый последующий элемент (байт/символ) хранится по последовательным (возрастающим) адресам памяти, как и другие массивы, — но поскольку строки представляют собой массивы байтов, не возникает вопроса о порядке байтов или порядка.
Однако если бы вы загрузили 32-битное слово из адреса строки «abcd», числовое значение в 32 битах будет отличаться на процессорах с прямым порядком байтов и с прямым порядком байтов. Но мы обычно не смотрим на числовые значения размера word/double/quad из строк (мы можем использовать больший размер для копирования строки из одного места в памяти в другое, не обращая внимания на числовые значения).
Привет, просто чтобы убедиться, что я понимаю, что, если я передам «2024» в int test(char* str)
, оно будет рассматриваться как массив или нет?
В C почти нет массивов. Массивы — это всего лишь хранилище. Как только вы используете в выражении массив, он сразу преобразуется в указатель, и мы берем его оттуда. Это мгновенное и автоматическое преобразование массива в указатель представляет собой операцию с потерями: как только указатель появляется, язык не знает, на сколько элементов ссылается этот указатель, на один элемент или на несколько. Итак, когда вы пишете test ( "2024" )
, «2024» генерирует инициализированный массив байтов в постоянной памяти программы (например, .rodata
), а для вызова test
компилятор передает адрес первой «2».
Итак, да, он обрабатывается как любой другой массив в C, то есть он немедленно преобразуется в указатель, и вызываемый здесь test
знает только тип элемента, на который ссылается указатель, но не длину, например . Мы могли бы изменить тест следующим образом int test ( char [] str )
, но это только предотвращает test
от изменения его формального параметра (т.е. str++ сейчас не разрешено), но это не информирует test
больше, чем char *str
(например, для test
до сих пор нет информации о длине массива).
Отсутствие порядка байтов влияет только на многобайтовые объекты.