В качестве комментария к комментарию от @Mark Wilkins & Co. Я пытаюсь показать, что определение может иметь эффект.
По делу:
fprintf()
принимает указатель, где он хранит то, что он прочитал. Он не знает тип, на который он указывает, но возьмите определение из формата и внесите аргумент . Что-то вроде sscanf("36", "%i", &my_dest);
-> number = va_arg(vl, int*);
Используйте правильные флаги для вас компилятор поймать эту
Когда Exec запускает программу, как правило, назначать адреса для неинициализированного данных (т.е. Int Foo;) в регион, известный как BSS. (См. Рисунок 1 ниже для рисунка).
На многих системах это было бы с низким адресом памяти и вверх.
Чтобы продемонстрировать, что происходит (в данной системе) мы имеем следующее:
Я начинаю со следующим:
/* global scope */
unsigned char unA;
unsigned char unB;
unsigned char unC;
unsigned int unD;
Список 1
В main()
я говорю:
unA = '1';
unB = '2';
unC = '3';
/* bit shifting the "string" NAC! into unD, reverse order as my system is LSB
* first (little-endian), unD becomes 558055758 => by byte ASCII !CNA */
unD = 0 | ('!' << 24) | ('C' << 16) | ('A' << 8) | 'N';
Список 2
И точка А без знака указателя обугленного к unA
и отвалам следующих 16 байт, которые результата:
отвалы в формате [полукокс < точки >], или гексе с ведущим нулевой (% с. или% 02x) *
+-- Address of unA
|
0x804b06c: 1.3.0000N.A.C.!. 2.00000000000000
| | |_____| |
| | | +--- unB
| | +--------- unD
| +------------------ unC
+-------------------- unA
Список 3
Тогда я изменить имя unB
к un2
, тот же порядок в файле:
unsigned char unA;
unsigned char un2;
unsigned char unC;
unsigned int unD;
Список 4
сейчас мой свал дает:
+-- Address of unA
|
0x804b06c: 1.3.2.00N.A.C.!. 0000000000000000
| | | |_____|
| | | +--------- unD
| | +---------------- unB
| +------------------ unC
+-------------------- unA
Список 5
Как можно видеть порядок адреса/выравнивание было изменено. Без изменений по типу, только по названию.
Назначение неправильного типа:
Следующий шаг затем бросить и диапазон переполнения типа. Изменить un2
назад unB
. У нас есть выравнивание, как в Список 3.
Мы создаем функцию, набор байтов (в системе с 4 байта/32bit INT), высокого порядка, как:
void set_what(unsigned int *n)
{
*n = 0 | ('t' << 24) | ('a' << 16) | ('h' << 8) | 'w';
/* or *n = 0x74616877; in an ASCII environment
* 0x74 0x61 0x68 0x77 == tahw */
}
Список 6
В main()
мы говорим:
/* dump */
set_what((unsigned int*)&unA);
/* dump */
Список 7
И получите:
0x804b06c: 1.3.0000N.A.C.!. 2.00000000000000
0x804b06c: w.h.a.t.N.A.C.!. 2.00000000000000
Список 8
Или:
set_what((unsigned int*)&unB); -> Yield:
0x804b06c: 1.3.0000N.A.C.!. 2.00000000000000
0x804b06c: 1.3.0000N.A.C.!. w.h.a.t.00000000
set_what((unsigned int*)&unC); -> Yield:
0x804b06c: 1.3.0000N.A.C.!. 2.00000000000000
0x804b06c: 1.w.h.a.t.A.C.!. 2.00000000000000
Список 9
Как можно видеть данные перезаписаны, независимо от типа и что "нет.
В некоторых условиях это приведет к SIGSEGV.
К проблемам вашего кода, как указано в предыдущих комментариях, но повторяю.
В декларациях вы говорите int steps
и в fscanf()
вы указываете %li
который является long int
и не int
. На quie несколько систем это могло бы иметь небольшой эффект, но на 64-битной системе все идет плохо.
Проверка на ассемблере:
Мы копируем код и сделать две копии, один с long int steps;
и один с int steps;
имени : lin_ok.c
и B: lin_bad.c
. Затем мы создаем некоторый вывод asm.
A $ cpp lin_ok.c > lin_ok_m32.i
A $ cpp lin_ok.c > lin_ok_m64.i
B $ cpp lin_bad.c > lin_bad_m32.i
B $ cpp lin_bad.c > lin_bad_m64.i
A $ gcc -std=c89 -m32 -S lin_ok_m32.i
A $ gcc -std=c89 -m64 -S lin_ok_m64.i
B $ gcc -std=c89 -m32 -S lin_bad_m32.i
B $ gcc -std=c89 -m64 -S lin_bad_m64.i
$ diff lin_ok_m32.s lin_ok_m64.s | head
9c9
< .comm steps,4,4 ; reserve 4 bytes
---
> .comm steps,8,8 ; reserve 8 bytes
...
Как можно видеть код предписывает, чтобы зарезервировать 8 байт на 64 бита и 4 на 32 бита (эта система) для steps
.
Если вы используете gcc, скомпилируйте с большим количеством флагов. Лично я использую, как правило:
НКУ -Wall- Wextra -pedantic -std = c89 -o основной main.c или -std=c99
, если в ней нуждается.
Это даст вам предупреждения о таких проблемах, как неправильный тип в scanf.
Пример компоновки работающего приложения. Он может быть совершенно иным, в зависимости от системы и т. Д., Но является aprox AFAIK. Надеюсь, я получил большую часть этого права.
________________ _________________
[ ] [ ]
[ ] [ Physical memory ]
[ Virtual memory ] <-- Translation --> [ ]
[ range ] table { - - - - - - - - }
[________________] [ ]
| [_________________]
|
+--+ high address : Virtual address
|
0xF00 +-------------------+'''''''''''''''''' Runnning env
| argv, env-vars, ..| |
0xBFF +-------------------+ | ptr
| stack | <- Running storage, where |
|... grows down ...| fun_a should return, local | 0xC0000000 on
| | variables, env, ... | linux Intel x86
| < huge area > | New frame allocated for |
| | recursive calls etc. |
|... grows up ...| |
| | <- Dynamic memory alloc. |
| heap | malloc, etc |
0x9e49+-------------------+ |
| double sizeX; | <- Uninitialized data |
bss | ... | BSS 000000 ... |
seg. | int nCellY | |
| int steps; | |
0x804c+-------------------+''''''''''''''''''''' Stored '| --- edata
data | | on |
seg. | int rank = 0; | <- Initialized data disk |
0x804b+-------------------+ : | --- etext
| main() | : |
text | mov ecx, edx | <- Instructions : | 0x08048000 on
seg. | ELF, or the like | Layout, link, etc : | linux Intel x86
0x8040+-------------------+ ''''''''''''''''''''''''''''''
|
+--- low address : Virtual address
Рис 1.
Ваша программа многопоточной? И что такое код для 'DEBUG'? – Shahbaz
Вы получаете предупреждения о компиляторе? Попробуйте выполнить компиляцию с помощью '-Wall -Wextra -pedantic' и посмотреть, получаете ли вы что-нибудь. – Collin
Также попробуйте определить 'nCellX', установив его равным некоторому начальному значению. Если это имя было инициализировано ранее (скажем, в MPI где-то), что приведет к ошибке – Collin