«Я понимаю, что автор имеет redeclared * time_ptr как указатель на unsigned char, но как ему удалось стать массивом (массив символов, я думаю)?»
Указатели указывают на память. Память - это массив байтов. Количество байтов, на которые указывает указатель, зависит от интерпретации (типа) предмета, на который указывает. Помимо этого простого факта компилятор не выполняет проверку границ в C/C++. Таким образом, по сути каждый указатель является указателем на массив элементов того типа, на который указывает указатель. Таким образом, указатель на unsigned char является указателем на массив однобайтовых символов. Указатель на структуру - это указатель на массив элементов, каждый из которых имеет размер одной структуры.
Так указатель на единую структуру IS указатель на массив размера 1. Ничто в языке не предотвращает плохой код и пытается получить доступ к элементу в следующем местоположении.
Это и сила, и проклятие указателей. И источник многих ошибок и проблем безопасности в C/C++. Кроме того, вы можете сделать много классных вещей на языке эффективно.
«С большой силой приходит большая ответственность».
Таким образом, этот код интерпретирует указатель структуры сначала как массив байтов и печатает шестнадцатеричный дамп, а затем как массив целых чисел. При обработке указателя как int * операция одиночного приращения перемещается на 4 байта.
Следовательно, первый элемент - 0x00000018 (малое значение для четырех байтов: 18 00 00 00). 0x18 гекс 24.
Второе целое является 0x00000016 (обратным порядком байтов 16 00 00 00) = 22.
И т.д.
Обратите внимание, что int * перемещается на 4 байта, потому что в вашем конкретном компиляторе sizeof(int) == 4
. «int» - это особый тип и может изменять размер на основе вашего компилятора. Если у вас был другой компилятор (скажем, для встроенного микроконтроллера), то sizeof (int) может быть 2, а целые числа будут распечатываться как 24, 0, 22 (при условии, что тот же самый блок памяти).
Is the size of C "int" 2 bytes or 4 bytes?
=== В ответ на комментарий ===
«(Accidentally прокомментировал где-то еще) Спасибо за ваш ответ. Тем не менее, есть одна вещь, которая кажется немного неясно. Скажем, у меня есть указатель на полукокс «с». Является ли указатель теперь указатель на массив символов размера 1?
YES. байтовый массив из одного байта.
Кроме того, просто чтобы убедиться, вы» вы указали, что указатель на одну структуру указатель на массив размером один.
ДА, но в этом случае размер одного элемента в массиве равен sizeof(mystruct)
, что, вероятно, больше, чем один байт.
Указать, что указатель на указатель на char, следовательно, приведет к тому, что размер массива будет больше 1 и будет массивом байтов, ответственным за шестнадцатеричный дамп.
ДА.
Следовательно, должен ли любой указатель, когда typecasted таким образом, приведет к этому хорошему распаду байта?
ДА. Вот как работают байты/память.
Еще одна вещь о ключевое слово sizeof(type)
. sizeof(type)
сообщает размер (в байтах) экземпляра type
. sizeof(variable)
эквивалентен sizeof (тип переменной). Это имеет тонкое поведение, когда переменная является указателем или массивом. Например:
char c = '0' // in memory this is the single byte 0x30
char str[] = { 0x31, 0x32, 0x00 }; // an array of bytes 0x31, 0x32, 0x00
sizeof(char) == sizeof(c) == 1
sizeof(str) == 3 // compiler knows the array was initialized to 3 bytes
sizeof(p) == 4 // assuming your compiler is using 32-bit pointers. On a 64-bit machine this would be 8.
char* p = &c; // note that assigning a pointer to the address of a variable requires the address-of operator (&)
sizeof(*p) == 1 // this is the size of the thing pointed to.
p = str; // note that assigning an ARRAY variable name to a pointer does not require address-of (because the name of an array IS a pointer - they *are* the same type in all ways except with respect to sizeof() where sizeof() knows the size of an initialized array.)
sizeof (*p) == 1; // even though p was assigned to str - an array - sizeof still returns the answer based on the type of the thing p is pointing to - in this case a single char. This is subtle but important. p points to a single character in the array.
// Thus at this point, p points to 0x31.
p++; // p advances in memory by sizeof(*p), now points at 0x32.
p++; // p advances in memory by sizeof(*p), now points at 0x00.
p++; // p advances in memory by sizeof(*p), now points BEYOND THE ARRAY.
ВАЖНО - Поскольку указатель был выдвинут в конце прошлого массива, в этой точке р указывает на возможно недействительна памяти или это может указывать на какой-либо другой случайной величины в памяти. Это может привести к сбою (в случае недопустимой памяти) или повреждению ошибки и памяти (и вероятной ошибке безопасности), если она указывает на «действительную» память, которая не используется, как ожидалось. В этом конкретном случае, когда предполагается, что переменные живут в стеке, он указывает на переменную или, возможно, на обратный адрес функции. В любом случае, выходя за пределы массива, BAD. ОЧЕНЬ ОЧЕНЬ ПЛОХО. и КОМПЬЮЛЕР НЕ ОСТАВИВАЕТ ВАС !!!
Также, кстати, sizeof
НЕ является функцией. Он оценивается компилятором во время компиляции на основе таблицы символов компилятора. Поэтому нет никакого способа, чтобы получить размер массива, выделенный так:
char* p = malloc(sizeof(char)*100);
компилятор не понимает, что вы выделить 100 байт, потому что таНос является функцией времени выполнения. (действительно, 100 обычно является переменной с изменяющимся значением). Поэтому sizeof(p)
вернет размер указателя (или 4 или 8, как упоминалось ранее), и sizeof(*p)
вернет sizeof(char)
, что равно 1. В таком случае код должен помнить, сколько памяти было выделено в отдельной переменной (или в другой путь - динамическое распределение - это отдельная тема).
Другими словами, SizeOf() работает только для типов и для статически инициализированных массивов (те, которые инициализируются в коде), например, такие:
char one[] = { 'a' };
char two[] = "b"; // using the string quotes results in a final zero-byte being automatically added. So this is an array of 2 bytes.
char three[3] = "c"; // the specified size overrides the string size, so this produces an array of 'c', 0, <uninitialized>
char bad[1] = "d"; // trying to put 2 bytes in a 1 byte-bag. This should generate a compiler error.
ii. Не напомнив мне о членах 'struct tm', я могу видеть из шестнадцатеричного дампа, сделанного' printf ("% 02x", raw_ptr [i]); 'что первые 12 байтов - это три 32-битных ints, потому что hex 18 = dec 24 (seconds), hex 16 = dec 22 (минуты), а 4 - часы. –
Благодарим вас за ответ. Однако есть одна вещь, которая кажется немного неясной. Предположим, у меня есть указатель на char 'c'. Является ли указатель теперь указателем на массив символов размером 1? Кроме того, просто для проверки вы упоминали, что указатель на одну структуру является указателем на массив размером один. Таким образом, указание указателя на указатель на char приведет к тому, что размер массива будет больше 1 и будет массивом байтов, ответственным за шестнадцатеричный дамп. Следовательно, если какой-либо указатель, когда придумано таким образом, приведет к этому хорошему распаду байта? –
Вы можете индексировать указатель *, как будто * это массив. C здесь никаких ограничений. Даже если вы указали указатель на ** одиночную ** переменную 'char', вы можете индексировать * точно так, как вам нравится * при условии чтения/записи запрещенной памяти или при написании искажения somthing, которое не вызывает * прямой * ошибки , но создаст проблему через некоторое время ;-) (вот почему ошибки указателя могут быть трудно отследить). Здесь указатель 'char *' был отличен из адреса 'struct', так что его содержимое может быть рассмотрено байтом байтом. –