Форум программистов, компьютерный форум, киберфорум
Низкоуровневое программирование
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/7: Рейтинг темы: голосов - 7, средняя оценка - 5.00
 Аватар для McLightning
0 / 0 / 0
Регистрация: 22.01.2023
Сообщений: 9

Деление на ноль

22.08.2023, 16:03. Показов 1916. Ответов 2
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Что будет если поделить на ноль в программе которая работает без операционной системы?
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
22.08.2023, 16:03
Ответы с готовыми решениями:

Возникает ошибка "Деление на ноль", когда на ноль ничего и нигде не делится
Написал программу, которая выводит на экран координаты клика мыши. SSEG segment stack db 256 dup(0) SSEG ends ...

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

Деление с остатком возвращает ноль
Написал процедуру для перевода в десятичный символьный вид, а при делении выдает деление на ноль. Нуля нету(по регистру посмотрел)...

2
Модератор
1245 / 676 / 292
Регистрация: 10.11.2019
Сообщений: 1,406
22.08.2023, 18:52
http://www.techhelpmanual.com/... rflow.html

Скорее всего, компьютер просто зависнет, если не установлен правильный обработчик INT0
(имеется ввиду реальный режим Intel 8086)
1
Эксперт Hardware
Эксперт Hardware
 Аватар для R71MT
6206 / 2441 / 402
Регистрация: 29.07.2014
Сообщений: 3,174
Записей в блоге: 4
22.08.2023, 22:34
Лучший ответ Сообщение было отмечено Mikl___ как решение

Решение

Цитата Сообщение от McLightning Посмотреть сообщение
Что будет если поделить на ноль
Деление на нуль - это исключение #DF (Divide Fault), а не прерывание.
Все исключения генерятся самим процессором, как реакция на ошибку в условиях при выполнении инструкций. Далее, по линии INTR (Request) сигнал IRQ об исключении #DF из ЦП поступает на линию(0) контролёра прерываний APIC, который преобразует IRQ в вектор/номер, и передаёт его обратно в ЦП. Сигналом по линии INTA (Acknowledgment) ЦП информирует APIC, что благополучно получил от него этот вектор (подтверждение).

А дальше уже интересней..
ЦП имеет регистр IDTR (Interrupt Descriptor Table), в котором должен лежать адрес "таблицы прерываний". В реальном режиме эта таблица известна как IVT (Int Vector Table), а в защищённом IDT - в этих таблицах хранятся адреса обработчиков исключений/прерываний. Получив от APIC вектор, ЦП берёт адрес IVT из своего регистра IDTR, и по вектору передаёт управление соответствующему обработчику. Такой алго обслуживания не зависит от режима работы процессора Real/Protected, и является для них общим.

При включении машины, созданием таблицы IVT занимается биос. Он прописывает в IVT векторы только своих обработчиков в диапазоне 00-1Fh, а далее ОС может дополнить IVT своими векторами, начиная с 20h и до FFh (итого 255 макс). После ребута, в регистр IDTR аппаратно кладётся значение нуль, и биос не трогает его. Тогда получается, что IVT в реальном режиме занимает самые нижние адреса физ.памяти 0000-0400h.


Таким образом, при ошибке деления на нуль управление передаётся тоже по вектору(0) (так настроен APIC). Если-бы биос не позаботился о заполнении IVT адресами своих обработчиков, то реакцией ЦП на исключение #DF был-бы внутренний сигнал #RESET, т.е. тупик и перезагрузка.

Если в момент #DF процессор находился в защищённом режиме РМ, значит его туда кто-то вогнал, и этот "кто-то" - загрузчик ОС. Поскольку код обработчиков биос в IVT 16-битный, то для 32/64-битного РМ они уже не подойдут, и загрузчику ОС приходится создавать новую таблицу IDT, и прописывать в неё свои процедуры обработки. IDT в РМ может находиться где угодно в памяти, лишь-бы её адрес был указан в регистре IDTR.

Можно провести в ядерном отладчике WinDbg небольшой эксперимент и посмотреть, как именно организована обработка исключений/прерываний в Win64. Здесь нужно отметить, что векторы в диапазоне 00-1Fh в РМ зарезервированы Intel для исключений, и все осе'писатели должны придерживаться этого правила.

Для начала запросим у WinDbg дамп таблицы IDT. В столбце(1) видим номера прерываний INT, в столбце(2) адреса их обработчиков, а первой записью оказалась как-раз "DivideErrorFault":

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
0: kd> !idt
   Dumping IDT: fffff80000b91080  ;//<--- адрес таблицы в памяти! (можно получить через "r @idtr")
 
Исключения процессора
 
00:   fffff80002c85f00  nt!KiDivideErrorFault
01:   fffff80002c86000  nt!KiDebugTrapOrFault
02:   fffff80002c861c0  nt!KiNmiInterrupt         Stack = 0xFFFFF80000BA3000
03:   fffff80002c86540  nt!KiBreakpointTrap
04:   fffff80002c86640  nt!KiOverflowTrap
05:   fffff80002c86740  nt!KiBoundFault
06:   fffff80002c86840  nt!KiInvalidOpcodeFault
07:   fffff80002c86a80  nt!KiNpxNotAvailableFault
08:   fffff80002c86b40  nt!KiDoubleFaultAbort     Stack = 0xFFFFF80000BA1000
09:   fffff80002c86c00  nt!KiNpxSegmentOverrunAbort
0a:   fffff80002c86cc0  nt!KiInvalidTssFault
0b:   fffff80002c86d80  nt!KiSegmentNotPresentFault
0c:   fffff80002c86ec0  nt!KiStackFault
0d:   fffff80002c87000  nt!KiGeneralProtectionFault
0e:   fffff80002c87140  nt!KiPageFault
10:   fffff80002c87500  nt!KiFloatingErrorFault
11:   fffff80002c87680  nt!KiAlignmentFault
12:   fffff80002c87780  nt!KiMcheckAbort          Stack = 0xFFFFF80000BA5000
13:   fffff80002c87b00  nt!KiXmmException
1f:   fffff80002cd3f10  nt!KiApcInterrupt
 
Программные прерывания
 
2c:   fffff80002c87cc0  nt!KiRaiseAssertion
2d:   fffff80002c87dc0  nt!KiDebugServiceTrap
2f:   fffff80002cd41f0  nt!KiDpcInterrupt
 
Аппаратные от физ.устройств
 
37:   fffff8000322f090  hal+0x12BC                       (KINTERRUPT fffff8000322f000)
3f:   fffff8000322f130  hal+0x12BC                       (KINTERRUPT fffff8000322f0a0)
51:   fffffa8002361510  i8042prt+0x2A04                  (KINTERRUPT fffffa8002361480)
52:   fffffa8002361b10  USBPORT+0x2D344                  (KINTERRUPT fffffa8002361a80)
61:   fffffa80023615d0  nuvserial+0x2B88                 (KINTERRUPT fffffa8002361540)
62:   fffffa8002361c90  ataport+0xCB4C                   (KINTERRUPT fffffa8002361c00)
71:   fffffa8002361690  nuvserial+0x2B88                 (KINTERRUPT fffffa8002361600)
72:   fffffa8002361d50  ataport+0xCB4C                   (KINTERRUPT fffffa8002361cc0)
82:   fffffa8002361bd0  ataport+0xCB4C                   (KINTERRUPT fffffa8002361b40)
92:   fffffa8002361390  portcls+0x689C                   (KINTERRUPT fffffa8002361300)
a2:   fffffa8002361e10  HDAudBus+0x3F20                  (KINTERRUPT fffffa8002361d80)
b1:   fffffa8002361f90  ACPI+0x119C8                     (KINTERRUPT fffffa8002361f00)
b2:   fffffa8002361450  i8042prt+0x8A70                  (KINTERRUPT fffffa80023613c0)
b3:   fffffa8002361990  USBPORT+0x2D344                  (KINTERRUPT fffffa8002361900)
c1:   fffff8000322f3b0  hal!HalInitializeProcessor+0x3E8 (KINTERRUPT fffff8000322f320)
d1:   fffff8000322f450  hal!HalReturnToFirmware+0xAA0    (KINTERRUPT fffff8000322f3c0)
d2:   fffff8000322f4f0  hal!HalReturnToFirmware+0xB3C    (KINTERRUPT fffff8000322f460)
df:   fffff8000322f310  hal!HalInitializeProcessor+0x388 (KINTERRUPT fffff8000322f280)
e1:   fffff80002c92fa0  nt!KiIpiInterrupt
e3:   fffff8000322f1d0  hal!HalInitializeProcessor+0x458 (KINTERRUPT fffff8000322f140)
fd:   fffff8000322f590  hal!HalInitializeProcessor+0x630 (KINTERRUPT fffff8000322f500)
fe:   fffff8000322f630  hal!HalInitializeProcessor+0x674 (KINTERRUPT fffff8000322f5a0)
ff:   0000000000000000
Каждая запись в IDT имеет свой формат, и описывается структурой _KIDTENTRY64 (в доках, записи называются дескрипторами). Сейчас нас интересует запись(0) #DF с адресом обработчика fffff800'02c85f00, и соответственно сама запись будет совпадать с началом таблицы IDT в памяти. Посмотрим на содержимое этой структуры:

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
0: kd> dt _KIDTENTRY64 @idtr
ntdll!_KIDTENTRY64
   +0x000  OffsetLow      : 0x5f00        ;// мл.word адреса обработчика
   +0x002  Selector       : 0x10          ;// регистр CS = 10h, код уровня ядра
   +0x004  IstIndex       : 0y000
   +0x004  Reserved0      : 0y00000 (0)
   +0x004  Type           : 0y01110 (0xe) ;// дескрипторы исключений имеют тип 0х0Е
   +0x004  Dpl            : 0y00          ;// кольцо(0) защиты (уровень привилегий)
   +0x004  Present        : 0y1           ;// сегмент на данный момент в памяти
   +0x006  OffsetMiddle   : 0x02c8        ;// ср.word адреса обработчика
   +0x008  OffsetHigh     : 0xfffff800    ;// ст.dword адреса 
   +0x00c  Reserved1      : 0
   +0x000  Alignment      : 0x2c88e00`00105f00
Если собрать значения полей 8,6,0, то получим в аккурат указанный в дампе адрес fffff800'02c85f00, который можно теперь дизассемблировать командой u - это именно то, как Win (не биос) обрабатывает исключение "Деление на нуль" (фрагмент):

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
0: kd> u fffff80002c85f00
nt!KiDivideErrorFault:
fffff800`02c85f00  4883ec08           sub     rsp,8
fffff800`02c85f04  55                 push    rbp
fffff800`02c85f05  4881ec58010000     sub     rsp,158h
fffff800`02c85f0c  488dac2480000000   lea     rbp,[rsp+80h]
fffff800`02c85f14  c645ab01           mov     byte ptr [rbp-55h],1
fffff800`02c85f18  488945b0           mov     qword ptr [rbp-50h],rax
fffff800`02c85f1c  48894db8           mov     qword ptr [rbp-48h],rcx
fffff800`02c85f20  488955c0           mov     qword ptr [rbp-40h],rdx
fffff800`02c85f24  4c8945c8           mov     qword ptr [rbp-38h],r8
fffff800`02c85f28  4c894dd0           mov     qword ptr [rbp-30h],r9
fffff800`02c85f2c  4c8955d8           mov     qword ptr [rbp-28h],r10
fffff800`02c85f30  4c895de0           mov     qword ptr [rbp-20h],r11
fffff800`02c85f34  f685f000000001     test    byte ptr [rbp+0F0h],1
fffff800`02c85f3b  7464               je      nt!KiDivideErrorFault+0xa1 (fffff800`02c85fa1)
fffff800`02c85f3d  0f01f8             swapgs
fffff800`02c85f40  654c8b142588010000 mov    r10,qword ptr gs:[188h]
fffff800`02c85f49  41f6420380         test    byte ptr [r10+3],80h
fffff800`02c85f4e  743c               je      nt!KiDivideErrorFault+0x8c (fffff800`02c85f8c)
fffff800`02c85f50  b9020100c0         mov     ecx,0C0000102h
fffff800`02c85f55  0f32               rdmsr
fffff800`02c85f57  48c1e220           shl     rdx,20h
fffff800`02c85f5b  480bc2             or      rax,rdx
......
А вот аппаратные прерывания обслуживаются немного иначе.
Возьмём к примеру INT-51h из дампа, как сигнал от контролёра клавиатуры i8042:
51: fffffa8002361510 i8042prt+0x2A04 (KINTERRUPT fffffa8002361480)

Поскольку его дескриптор лежит не в начале IDT, нужно указать смещение так (в стиле С++):
Code
1
2
3
4
5
6
7
8
9
10
11
12
0: kd> dt @idtr + @@c++(0x51 * sizeof(nt!_KIDTENTRY64)) nt!_KIDTENTRY64
   +0x000  OffsetLow      : 0x1510
   +0x002  Selector       : 0x10
   +0x004  IstIndex       : 0y000
   +0x004  Reserved0      : 0y00000 (0)
   +0x004  Type           : 0y01110 (0xe)
   +0x004  Dpl            : 0y00
   +0x004  Present        : 0y1
   +0x006  OffsetMiddle   : 0x0236
   +0x008  OffsetHigh     : 0xfffffa80
   +0x00c  Reserved1      : 0
   +0x000  Alignment      : 0x2368e00`00101510
В силу того, что аппаратуры в системе много, здесь всплывает понятие IRQL, или уровень запроса "IRQ Level". Чем больше значение IRQL, тем приоритетнее считается запрос к ЦП на прерывание, а все остальные запросы с меньшим IRQL ставятся в очередь и обслуживаются позже, механизмом DPC "Deferred Procedure Call" (вызов отложенных процедур). В х32 было аж 32 уровня IRQL (0-31), а в х64 их урезали до 16-ти.

Состояние потока с отложенным вызовом сохраняется в стеке ядра - это структура "KTRAP_FRAME". Весь инфо-блок об аппаратном запросе заворачивается в основную структуру "KINTERRUPT" - команда отладчика !idt указывает её адрес в скобках. Если запросить содержимое данной структуры, можно обнаружить в ней много интересного:

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
0: kd> dt _KINTERRUPT fffffa8002361480
nt!_KINTERRUPT
   +0x000  Type                  : 0n22
   +0x002  Size                  : 0n160
   +0x008  InterruptListEntry    : _LIST_ENTRY [ 0x00000000`00000000 - 0x0 ]
   +0x018  ServiceRoutine        : 0xfffff880`02dc0a04
   +0x020  MessageServiceRoutine : (null)
   +0x028  MessageIndex          : 0
   +0x030  ServiceContext        : 0xfffffa80`02cc79f0
   +0x038  SpinLock              : 0
   +0x040  TickCount             : 0
   +0x048  ActualLock            : 0xfffffa80`02cc7b50
   +0x050  DispatchAddress       : 0xfffff800`02c84e70   nt!KiInterruptDispatch+0
   
   +0x058  Vector                : 0x51     ;//<---- IRQ
   +0x05c  Irql                  : 0x5      ;//<---- IRQL запроса (нуль - самый низкий)
   +0x05d  SynchronizeIrql       : 0xb  
   +0x05e  FloatingSave          : 0
   +0x05f  Connected             : 0x1
   +0x060  Number                : 0
   +0x064  ShareVector           : 0
   +0x065  Pad                   : [3]
   +0x068  Mode                  : 1   (Latched)
   +0x06c  Polarity              : 0   (InterruptPolarityUnknown)
   +0x070  ServiceCount          : 0
   +0x074  DispatchCount         : 0
   +0x078  Rsvd1                 : 0
   +0x080  TrapFrame             : 0xfffff800`00b98ac0 _KTRAP_FRAME
   +0x088  Reserved              : (null)
   +0x090  DispatchCode          : [4] 0x8d485550
Помимо номеров IRQ/IRQL и прочей инфы,
в хвосте лежит адрес фрейма "TRAP" - он позволяет вернуть прерванный поток к жизни после вызова DPC.

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
0: kd> dt fffff800`00b98ac0 _KTRAP_FRAME
ntdll!_KTRAP_FRAME
   +0x000  P1Home           : 0x50
   +0x008  P2Home           : 1
   +0x010  P3Home           : 0xfffff800`00b98b40
   +0x018  P4Home           : 0xfffffa80`02361cc0
   +0x020  P5               : 0xfffff880`0f0e9788
   +0x028  PreviousMode     : 0 ''
   +0x029  PreviousIrql     : 0 ''
   +0x02a  FaultIndicator   : 0xc6 ''
   +0x02b  ExceptionActive  : 0 ''
   +0x02c  MxCsr            : 0x1f80
   +0x030  Rax              : 0x1dcd5
   +0x038  Rcx              : 0xfffffa80`02d13fa0
   +0x040  Rdx              : 0
   +0x048  R8               : 0xfffffa80`04322b80
   +0x050  R9               : 0xffffffff
   +0x058  R10              : 0xfffff880`00c2f2eb
   +0x060  R11              : 0xfffff800`02e07e80
   +0x068  GsBase           : 0xfffffa80`022f97d0
   +0x068  GsSwap           : 0xfffffa80`022f97d0
   +0x070  Xmm0             : _M128A
   +0x080  Xmm1             : _M128A
   +0x090  Xmm2             : _M128A
   +0x0a0  Xmm3             : _M128A
   +0x0b0  Xmm4             : _M128A
   +0x0c0  Xmm5             : _M128A
   +0x0d0  FaultAddress     : 0xfffff800`00b92080
   +0x0d0  ContextRecord    : 0xfffff800`00b92080
   +0x0d0  TimeStampCKCL    : 0xfffff800`00b92080
   +0x0d8  Dr0              : 0x22
   +0x0e0  Dr1              : 0
   +0x0e8  Dr2              : 0
   +0x0f0  Dr3              : 1
   +0x0f8  Dr6              : 0xfffffa80`04322b80
   +0x100  Dr7              : 0
   +0x108  DebugControl         : 0xfffff880`00c2f114
   +0x110  LastBranchToRip      : 0xfffffa80`025d31a0
   +0x118  LastBranchFromRip    : 0
   +0x120  LastExceptionToRip   : 0xfffffa80`025d31a0
   +0x128  LastExceptionFromRip : 0
   +0x108  LastBranchControl    : 0xfffff880`00c2f114
   +0x110  LastBranchMSR        : 0x25d31a0
   +0x130  SegDs            : 0
   +0x132  SegEs            : 0
   +0x134  SegFs            : 0
   +0x136  SegGs            : 0
   +0x138  TrapFrame        : 0xfffff880`0f1494b6
   +0x140  Rbx              : 0xfffffa80`025d31a0
   +0x148  Rdi              : 0xfffff800`00b98c40
   +0x150  Rsi              : 0
   +0x158  Rbp              : 0xfffffa80`025d43f0
   +0x160  ErrorCode        : 0x1dcd5
   +0x160  ExceptionFrame   : 0x1dcd5
   +0x160  TimeStampKlog    : 0x1dcd5
   +0x168  Rip              : 0xfffff880`03fed9c2
   +0x170  SegCs            : 0x10
   +0x172  Fill0            : 0 ''
   +0x173  Logging          : 0 ''
   +0x174  Fill1            : [2] 0
   +0x178  EFlags           : 0x246
   +0x17c  Fill2            : 0
   +0x180  Rsp              : 1
   +0x188  SegSs            : 0
   +0x18a  Fill3            : 0
   +0x18c  CodePatchCycle   : 0n0
4
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
22.08.2023, 22:34
Помогаю со студенческими работами здесь

Деление на ноль (хотя я не делю на ноль)
.model small .stack 300h .data tabw dw -1135h,2326h dw 2A76h,0458h tabb dw 16h,9ah dw 32h,86h .CODE beg:mov ax,@data ...

Деление на ноль - ошибка
Ребята, помогите пожалуйста. я уже запарился, что ему надо?? Это только часть программы, но на этом этапе с ума схожу: program...

Сделать, чтобы при попытке деления на ноль, выводилось сообщение: «Деление на ноль»
Создайте консольное приложение. В нем реализуйте нахождение значения выражения 1/(x+n), где n – ваш вариант, а вместо х должно вводиться...

Деление на ноль
Вот основная программа (спасибо тем, кто помог написать её, многое понял): {$ASMMODE INTEL} var x,a,b:longint; begin ...

Деление на ноль
Перепробовал все подряд, в том числе и изменение интервалов. Никак не получается построить поверхность. И такая проблема с любой функцией...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
3
Ответ Создать тему
Новые блоги и статьи
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
Расскажи мне о Мире, бродяга
kumehtar 12.11.2025
— Расскажи мне о Мире, бродяга, Ты же видел моря и метели. Как сменялись короны и стяги, Как эпохи стрелою летели. - Этот мир — это крылья и горы, Снег и пламя, любовь и тревоги, И бескрайние. . .
PowerShell Snippets
iNNOKENTIY21 11.11.2025
Модуль PowerShell 5. 1+ : Snippets. psm1 У меня модуль расположен в пользовательской папке модулей, по умолчанию: \Documents\WindowsPowerShell\Modules\Snippets\ А в самом низу файла-профиля. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru