Ну я примеры не приводил, а только описал. В том-то и дело,...20.05.04 14:30 Число просмотров: 1497 Автор: DPP <Dmitry P. Pimenov> Статус: The Elderman Отредактировано 20.05.04 14:31 Количество правок: 1
> соответственно, печатается не hello world, а мусор.. > если в b.c написать str[] = "hello world", тогда всё окей, > выводится сама строка.. > и наоборот, тобишь тип должен быть одинаковым в обеих > файлах.. > > вопрос! почему тогда компилятор не ругается на > несоответствие типов? > испытания проводились под gcc, выжалстудию, и интеловский > компилятор.. результат одинаковый
Ну я примеры не приводил, а только описал их. В том-то и дело, что везде описано, что str[] и *str идентичны! А на деле-то совсем не так. Мало того и не может быть так. Ну а не ругается, потому что по правилам языка типы то соответствуют.
- при определении переменной интегрального типа вне функции
п-нная заносится в сегмент _BSS, обращение происходит посредством
прямой адресации памяти(например, byte ptr). инкрементирование значения
п-нной происходит через РОН.
если определить переменную вне функции с инициализацией начального
значения - п-нная заносится в _DATA.
при объявлении переменной внутри функции обращение п-нной
происходит как смещение относительно ebp, в котором находится
значение stack pointer`a для данной функции.
при объявлении глобальной переменной с модификатором volatile блок кода,
где используется данная переменная не оптимизируется
- массив
при объявлении массива вне функции без указания размерности добавляется модификатор
EXTRN, обращение к ячейкам массива происходит через идентификатор массива плюс смещение
в опт режиме цикл с обращениями к такому массиву раскладывается по отдельным итерациям.
(такая оптимизация происходит при малом значении итераций).
если объявить массив вне функции с указанием его длины, то массив помещается в сегмент
_BSS.
при объявлении указателя вне функции, ук-ль заносится в _BSS(в случае если этот ук-ль
не инициализируется или если ему присваивается значение оператора new). Если
присвоить указателю числовую константу - в _DATA. при обращении к ячейки памяти происходит
копирование значения указателя из памяти в регистр(например, есх или еах) и далее
запись/чтение через значение этого регистра с соответствующим сдвигом.
при объявлении массива без размерности в функции компилятор выдает ошибку. Если
инициализировать значение длины массива, то выделяется место в стеке (значение stack
pointer`a смещается на n*размер данных). при обращении к массиву используется
адресация по базе со смещением.
- поля структур
при объявлении структуры вне функции, она помещается в _BSS, если неинициализирована,
и в _DATA при задании начальных значений. в обоих случаях обращение к структуре
происходит посредством прямой адресации плюс смещение от начала структуры в зависимости
от поля. если структуру объявить с модификатором const, то она будет помещена в
CONST.
если структура объявлена внутри функции, то ст-ра размещается в стеке и обращение к полям
происходит относительно ebp.
при передаче структуры в качестве параметра через ссылку - передается
адрес(lea).
- члены классов
обращение к полям классов осуществляется так же как и к членам структур. при
вызове функций - членов классов, в качестве параметра неявно передается указатель this
(адрес объекта данного класса обычно заносится в регистр есх и передается в функцию
через этот регистр). конструктор в конце помещает в регистр еах значение this.
когда доступ к полю объекта осуществляется в функции(объект передается как параметр),
объект полностью кладется в стек в качестве аргумента(если объект объявлен внутри функции,
то при вызове функции происходит повторное копирование объекта в стеке, либо если
объект объявлен вне функции, то происходит копирование из _DATA либо _BSS в стек).
в функции обращение к полям относительно ebp.
при наличии виртуальных методов в классе, вначало каждого объекта помещается
адрес таблицы виртуальных методов(4 байта).
вызов виртуального метода:
- в регистр есх кладется адрес объекта(this).
- регистр(например, еах или еdх) заносится значение адреса ТВМ
и далее вызов ВМ командой call,
в данном случае (при наличии таблицы) первое поле объекта расположено за таблицей,
поэтому доступ к полю осуществляется с некоторым сдвигом от адреса объекта.
соответственно такое смещение не менее 4.
скажем, если имеется класс:
class base {
public:
char Char1;
virtual void Func1()
{
...
}
virtual void Func2()
{
...
}
};
то при обращении ко второму ВМ будет сгенерировано:
mov ecx, DWORD PTR _b$[ebp] ;адрес объекта в есх
mov edx, DWORD PTR [ecx] ;первые 4 байта (адрес ТВМ) в edx
mov ecx, DWORD PTR _b$[ebp] ;this в ecx
call DWORD PTR [edx+4] ;вызов виртуального метода,
;т.к. метод второй то смещение в таблице 4
далее, при обращении к полю Char1
mov eax, DWORD PTR _b$[ebp] ;адрес объекта в есх
mov BYTE PTR [eax+4], 78 ;заносим значение в байт (адрес объекта+4),
;(с учетом ТВМ)
если определить класс как:
class base {
public:
char Char1;
};
то оператор sizeof возвратит значение 1.
если :
class base {
public:
char Char1;
virtual void Func1()
{
...
}
virtual void Func2()
{
...
}
};
то sizeof возвратит 8.
без объявления виртуальных методов обращение к полям осуществляется от
адреса объекта(т.е. без дополнительного смещения на 4 байта).
P.S. писал не я
а чего, примерно так оно всё и есть.. только написано как-то криво..14.05.04 16:15 Автор: zelych Статус: Member
это и есть фишка от макара... ромина пятая лаба... он просто писал этот отчёт будучи под воздествием веществ, искажающих его восприятие мира..... макар его минут 20 распекал, что рома писать не умет :), он обиделся и попросил что-бы его художества оценили :)
> это и есть фишка от макара... ромина пятая лаба... он > просто писал этот отчёт будучи под воздествием веществ, > искажающих его восприятие мира..... макар его минут 20 > распекал, что рома писать не умет :), он обиделся и /|\ > попросил что-бы его художества оценили :) | |
прошу принять во внимание при прочтении сего сообщения | следующие несколько фактов, которые
не были указаны достопочтеннейшим г-ном noiZe, но которые стоят того, чтобы их изложили:
1. прежде всего это то, что все имена вымышлены. Таких людей (рома,макар) никогда не существовало
на планете Земля и всякое сходство является только случайностью и не более того.
2. хим вещества не являются чем то противоречащим конституции и законодательству РФ
3. никакой рома не обижался никакого макара (прошу особо отметить этот пункт).
Здесь-то под многими системами разницы не будет ни какой,...14.05.04 16:47 Автор: DPP <Dmitry P. Pimenov> Статус: The Elderman
> особенно не вчитывался, но по поводу что в какие сегменты > кладётся - вроде правильно.. > > ЗЫЖ почему-то вспомнилась заморочка от макара: > чем отличается > > void f() > { > char *str1 = "hello world"; > // от > char str2[] = "hello world"; > // ... > } Здесь-то под многими системами разницы не будет ни какой, правда под Линуксом возникнет ошибка во время выполнения если написать str1[ 0 ] = 'H', а при выполнении str2[ 0 ] = 'H' ошибки не возникнет.
Раз уж зашла тема про массивы и указатели, напишу про один вопросик, который до сих пор не разрешен и покоя мне не дает. В двух разных модулях используется один массив, в одном описан, в другом определен:
char str[] = "hello, world.";
в одном, а в другом
extern char *str;
Причем, естественно extern может присутствовать в первом, и, естественно, отсутствовать во втором. Работа с массивом компилироваться должна с точки зрения языка одиннаково исходя из равнозначности описания и по разному исходя из здравого смысла. А именно оператор *str = 'H' должен дать разные коды для корректной работы.
1)
lea bx, str
mov byte ptr[bx], 'H'
или
mov bx, offset str
mov byte ptr[bx], 'H'
или
mov al, 'H'
mov str, al
если str определен как
str db 'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '.', 0
или
str label byte
db 'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '.', 0
2)
mov bx, str
mov byte ptr[bx], 'H'
если str описан как
str dw tmp
tmp db 'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '.', 0
Неоднозначность какая-то имеет место быть по-моему...
не, у загадки есть более интерестное решение..15.05.04 00:50 Автор: zelych Статус: Member
...
> дает. В двух разных модулях используется один массив, в > одном описан, в другом определен: > char str[] = "hello, world."; > в одном, а в другом > extern char *str; > Причем, естественно extern может присутствовать в первом, > и, естественно, отсутствовать во втором. Работа с массивом
может я чего не понял, но, кажется, компилятор не даст написать
extern char str[] = "...";
да и в первом случае, строка будет лежать в сегменте констант, поэтому
*str = 'H';
делать нельзя.. разве что в досе только..
хотя надо попробовать..
> Неоднозначность какая-то имеет место быть по-моему...
собственно, отгадка..19.05.04 16:22 Автор: zelych Статус: Member
> может я чего не понял, но, кажется, компилятор не даст > написать > extern char str[] = "..."; Ну да, естественно, не будем инициализировать внешний массив. Смысл в том, чтоб внешним был не указатель а массив. Пусть будет просто extern char str[ 1 ]; ничто не мешает в другом модуле обратиться к последующим элементам.
> да и в первом случае, строка будет лежать в сегменте > констант, поэтому > *str = 'H'; > делать нельзя.. разве что в досе только.. Ну не писать, а читать. Пусть будет printf( "%c", *str );
> хотя надо попробовать.. > > > Неоднозначность какая-то имеет место быть по-моему...
забавный эффект получается..19.05.04 16:14 Автор: zelych Статус: Member
соответственно, печатается не hello world, а мусор..
если в b.c написать str[] = "hello world", тогда всё окей, выводится сама строка..
и наоборот, тобишь тип должен быть одинаковым в обеих файлах..
вопрос! почему тогда компилятор не ругается на несоответствие типов?
испытания проводились под gcc, выжалстудию, и интеловский компилятор.. результат одинаковый
Ну я примеры не приводил, а только описал. В том-то и дело,...20.05.04 14:30 Автор: DPP <Dmitry P. Pimenov> Статус: The Elderman Отредактировано 20.05.04 14:31 Количество правок: 1
> соответственно, печатается не hello world, а мусор.. > если в b.c написать str[] = "hello world", тогда всё окей, > выводится сама строка.. > и наоборот, тобишь тип должен быть одинаковым в обеих > файлах.. > > вопрос! почему тогда компилятор не ругается на > несоответствие типов? > испытания проводились под gcc, выжалстудию, и интеловский > компилятор.. результат одинаковый
Ну я примеры не приводил, а только описал их. В том-то и дело, что везде описано, что str[] и *str идентичны! А на деле-то совсем не так. Мало того и не может быть так. Ну а не ругается, потому что по правилам языка типы то соответствуют.
непонятно как-то..20.05.04 15:44 Автор: zelych Статус: Member
> в том-то и дело, что не идентичны.. > то, что описано в другом моём посте - это в соответствии со > стандартом
И я говорю, что на практике не идентичны, а в соответствии со стандартом должны быть идентичны.
> просто какое-то не совсем логичное поведение компиляторов.
Как же не логичное. Компиляторы генерят код по описанию. Просто в стандарте надо указать, что *str и str[] совершенно разные вещи! Только для удобства программеров сделано так, что обращение к элементам по *str и str[ 0 ] эквивалентны, как и циклическая обработка векторов по *str++ и str[ i++ ], где, разумеется, в первом случае изменяется сам указатель, а во втором только индекс, и, опять же, первая конструкция совсем не применима, если str был описан как массив, а не указатель.