Подробнее
@System32Com¡cs
it-юмор,geek,Прикольные гаджеты. Научный, инженерный и айтишный юмор,system32Comics,Смешные комиксы,веб-комиксы с юмором и их переводы,без перевода,it humor,geek,system32Comics,comics
Скорее всего тут игра слов, завязанная на том, что byte - укус и byte - столько занимает char в некоторых ОС. Просто тупая игра слов, не завязанная на особенностях выделения памяти и ссылок.
chat занимает 1 байт, с выравниванием по 4. Но тут-то не char, тут ссылка на массив из char. Ссылка занимает 4, а массив занимает столько, сколько ему выделят.
Память под элементы массива обычно выделяется в куче, а значит в RAM. Один элемент вполне может занимать байт. А ссылку на массив обычно кладут в переменную, а значит на стек. На картинке идет речь про RAM, а значит скорее всего речь про значения массива, а не про ссылку на первый элемент.
В языке C есть две разные сущности: указатель как отдельная переменная, которой программист может присваивать адрес области памяти и символ в таблице символов компилятора, с которым такое сделать нельзя. Под первое тратится память программы в сегменте данных или в куче или на стеке, под второе нет. char[] это второе, это символ компилятора, а не указатель, память тратится только под сам массив, но не существует адресуемой области памяти программы, где дополнительно хранился бы адрес этого массива.
Короче, char[] ни разу не указатель, несмотря на то, что может использоваться в адресной арифметике как константа.
Если ты имеешь в виду char[] как тип, то конечно же он не тратит нисколько памяти, но и получить ее не может. Так что это сразу мимо.
А вот переменная типа char[] занимает 4 байта, как и все указатели.
Полагаю, что художник просто перепутал char и char[]
> но и получить ее не может. Так что это сразу мимо.
Может. Твои познания в C сильно устарели.
> А вот переменная типа char[] занимает 4 байта, как и все указатели.
char[] ни разу не указатель, это массив. Массив и указатель в C разные вещи.
Может, на примере будет проще:
char ch; /* символ */
char array[1]; /* массив символов */
ch занимает ровно один байт и нет такого места в памяти программы, где хранился бы адрес ch, это символ времени компиляции, а во время исполнения это просто фиксированное смещение от начала сегмента данных или на стеке и это смещение - константа времени выполнения, поменять её нельзя. Хотя можно поменять значение самого ch, разумеется. Ровно то же самое с array - это точно такой же символ компилятора и точно так же ему нельзя присвоить никакого другого значения.
char* pch = &array[0];
А вот тут явным образом выделено дополнительное место под указатель на начало массива и несмотря на то, что синтаксис C позволяет использовать pch вместо array, указатель не массив. В pch можно засунуть другой адрес (например, &ch), потому что pch - переменная, не фиксированное смещение от начала сегмента данных.
Ты прав в том смысле, что char xx[] - в С создает массив из символов указанных сразу же. Но я еще раз повторю, что этот случай не имеет смысла, поскольку на него выделяется памяти столько требуется с поправкой на границу. Да и сам тип все равно называется char, а не Char[]
А вот в других языках, Type[] - обозначение ссылки на массив из типов с неопределенной заранее длиной массива.
Нет, sizeof(char) строго равно 1 по определению и это явным образом прописано в стандарте C.
Проблемы выравнивания это платформенно-зависимая штука, на разных архитектурах по разному и где-то вообще нет никакого выравнивания. В любом случае этот вопрос не имеет отношения к размеру char, который всегда занимает один октет.
> Да и сам тип все равно называется char, а не Char[]. А вот в других языках, Type[] - обозначение ссылки на массив из типов с неопределенной заранее длиной массива.
В современном C тоже. Ты можешь написать char a[] = "строка". Современный C даже поддерживает char a[n] внутри функции, где n это аргумент функции, выделяя на стеке массив переменного размера в момент входа в функцию. Так что char[] это тип в C, читай свежий стандарт.
Зависит от кучи вещей, включая архитектуру, компилятора (не)использования #pragma pack(n). А вот еслит добавить в определение структуры __packed, то структура будет без выравнивания и размер будет равен 1+sizeof(p), так как sizeof(char)==1 по определению. Такое бывает нужно при обмене бинарными данными фиксированного формата по сети или через бинарные файлы.
Только всё это не имеет отношения к размеру памяти, занимаемой самой переменной, потому что в этот размер выравнивание не входит, это накладные расходы.
> некая сущность обращается за выделением памяти.
Память под char[] вполне себе выделяется. Например, в ранних версиях стандарта C программы делали так:
strict data {
size_t length;
char array[1];
} s;
После чего под s можно выделить в куче произвольное количество памяти, более чем sizeof(length) и свободно адресовать array[N] любыми значениями до соответствующей длины. А в современном C можно даже опустить единичку в описании структуры и всё будет работать при условии аккуратного кодинга.
Дефолтные настройки, gcc, x64. Давай, не стесняйся.
> Только всё это не имеет отношения к размеру памяти, занимаемой самой переменной, потому что в этот размер выравнивание не входит, это накладные расходы.
Как раз наоборот, именно это и является размером памяти, реально занимаемой переменной, что подтверждает sizeof от стракта из приведенного мной примера.
> Память под char[] вполне себе выделяется
В твоем примере память выделяется под стракт, а не под какой-то конкретный его элемент. И указатель у тебя будет на этот самый стракт.
Не, никто не мешает тебе, конечно, выделить сколько угодно памяти и сдвинуть указатель на любое число байт, но это уже из серии выстрела в ногу.
Короче, я еще раз подытожу.
1. Если на картинке С, то Char[] - это не название типа, это название переменной, потому что типа Char[] в C не существует.Тип этой переменной мы не знаем, но это не важно, потому что в C переменные xxx[] не динамические и не нуждаются в "запрашивании" выделения памяти.
2. Если на картинке не C, тогда Char[] - это обозначение динамического массива из типов Char, для которого будет использоваться указатель (да, даже в языках высокого уровня).
А как программа знает где этот массив? И так и так где-то будет хранится адрес. С указателем будет хранится еще и адрес самого указателя. Максимум как можно укоротить данные это если они являются частью команды процессора. Тогда они будут занимать место в скомпилированном коде без адреса. Типа mov ah,09h
> А как программа знает где этот массив? И так и так где-то будет хранится адрес.
Нигде не хранится во время выполнения. Компилятор вставляет в код фиксированное смещение относительно начала сегмента данных (или от вершины стека) из своей таблицы символов, которая существует только во время компиляции.
Не в исходном коде. В машинном коде, в операндах машинных команд. "Где угодно" в данном случае не отменяет того, что в языке C указатель и массив не одно и то же.
Нет, в сегменте данных и в стеке они не потребляют больше байта данных. Всё остальное не имеет отношения к языку C как таковому (где вообще осмысленно выражение "тип данных") и представляют собой проблемы кодогенератора. Сегменты данных и сегменты кода - разные штуки.
Короче, char[] ни разу не указатель, несмотря на то, что может использоваться в адресной арифметике как константа.
А вот переменная типа char[] занимает 4 байта, как и все указатели.
Полагаю, что художник просто перепутал char и char[]
Может. Твои познания в C сильно устарели.
> А вот переменная типа char[] занимает 4 байта, как и все указатели.
char[] ни разу не указатель, это массив. Массив и указатель в C разные вещи.
Может, на примере будет проще:
char ch; /* символ */
char array[1]; /* массив символов */
ch занимает ровно один байт и нет такого места в памяти программы, где хранился бы адрес ch, это символ времени компиляции, а во время исполнения это просто фиксированное смещение от начала сегмента данных или на стеке и это смещение - константа времени выполнения, поменять её нельзя. Хотя можно поменять значение самого ch, разумеется. Ровно то же самое с array - это точно такой же символ компилятора и точно так же ему нельзя присвоить никакого другого значения.
char* pch = &array[0];
А вот тут явным образом выделено дополнительное место под указатель на начало массива и несмотря на то, что синтаксис C позволяет использовать pch вместо array, указатель не массив. В pch можно засунуть другой адрес (например, &ch), потому что pch - переменная, не фиксированное смещение от начала сегмента данных.
От 1 до 4, но не суть.
Ты прав в том смысле, что char xx[] - в С создает массив из символов указанных сразу же. Но я еще раз повторю, что этот случай не имеет смысла, поскольку на него выделяется памяти столько требуется с поправкой на границу. Да и сам тип все равно называется char, а не Char[]
А вот в других языках, Type[] - обозначение ссылки на массив из типов с неопределенной заранее длиной массива.
Нет, sizeof(char) строго равно 1 по определению и это явным образом прописано в стандарте C.
Проблемы выравнивания это платформенно-зависимая штука, на разных архитектурах по разному и где-то вообще нет никакого выравнивания. В любом случае этот вопрос не имеет отношения к размеру char, который всегда занимает один октет.
> Да и сам тип все равно называется char, а не Char[]. А вот в других языках, Type[] - обозначение ссылки на массив из типов с неопределенной заранее длиной массива.
В современном C тоже. Ты можешь написать char a[] = "строка". Современный C даже поддерживает char a[n] внутри функции, где n это аргумент функции, выделяя на стеке массив переменного размера в момент входа в функцию. Так что char[] это тип в C, читай свежий стандарт.
Вот тебе классический пример:
struct data {
char p;
int i;
};
Чему равен sizeof(struct data)) ?
> Что значит "не имеет смысла"?
Это значит, что ситуация не имеет смысла в контексте обсуждаемого комикса, где некая сущность обращается за выделением памяти.
Зависит от кучи вещей, включая архитектуру, компилятора (не)использования #pragma pack(n). А вот еслит добавить в определение структуры __packed, то структура будет без выравнивания и размер будет равен 1+sizeof(p), так как sizeof(char)==1 по определению. Такое бывает нужно при обмене бинарными данными фиксированного формата по сети или через бинарные файлы.
Только всё это не имеет отношения к размеру памяти, занимаемой самой переменной, потому что в этот размер выравнивание не входит, это накладные расходы.
> некая сущность обращается за выделением памяти.
Память под char[] вполне себе выделяется. Например, в ранних версиях стандарта C программы делали так:
strict data {
size_t length;
char array[1];
} s;
После чего под s можно выделить в куче произвольное количество памяти, более чем sizeof(length) и свободно адресовать array[N] любыми значениями до соответствующей длины. А в современном C можно даже опустить единичку в описании структуры и всё будет работать при условии аккуратного кодинга.
Дефолтные настройки, gcc, x64. Давай, не стесняйся.
> Только всё это не имеет отношения к размеру памяти, занимаемой самой переменной, потому что в этот размер выравнивание не входит, это накладные расходы.
Как раз наоборот, именно это и является размером памяти, реально занимаемой переменной, что подтверждает sizeof от стракта из приведенного мной примера.
> Память под char[] вполне себе выделяется
В твоем примере память выделяется под стракт, а не под какой-то конкретный его элемент. И указатель у тебя будет на этот самый стракт.
Не, никто не мешает тебе, конечно, выделить сколько угодно памяти и сдвинуть указатель на любое число байт, но это уже из серии выстрела в ногу.
Короче, я еще раз подытожу.
1. Если на картинке С, то Char[] - это не название типа, это название переменной, потому что типа Char[] в C не существует.Тип этой переменной мы не знаем, но это не важно, потому что в C переменные xxx[] не динамические и не нуждаются в "запрашивании" выделения памяти.
2. Если на картинке не C, тогда Char[] - это обозначение динамического массива из типов Char, для которого будет использоваться указатель (да, даже в языках высокого уровня).
Что значит "не имеет смысла"? Это работает и никаких дополнительных указателей на начало массива не существует.
Нигде не хранится во время выполнения. Компилятор вставляет в код фиксированное смещение относительно начала сегмента данных (или от вершины стека) из своей таблицы символов, которая существует только во время компиляции.