Расположение объявлений переменных в C определяет, какая из них будет выполнена? - PullRequest
0 голосов
/ 30 апреля 2018

Нужна серьезная помощь - я столкнулся с очень странной проблемой.

Моя программа - это программа, которая определяет различные структуры в файле библиотеки Test.h. Это Test.h файл:

typedef struct InstructionFields{ 
  unsigned int op;         /* opcode: bits 31-26 */
  unsigned int rs;         /* first register source operand: bits 25-21 */
  unsigned int rt;         /* second register source operand: bits 20-16 */
  unsigned int rd;          /* destination register: bits 15-11 */
  unsigned int shamt;      /* shift amount: bits 10-6 */
  unsigned int immedOrAddress;      /* constant or address: bits 15-0 */ 
  unsigned int target;    /* jump target: bits 25-0 */
  unsigned int funct;      /* function: bits 5-0 */
} IF, *IF_ptr;

typedef struct ControlSignalsList{ 
  unsigned int RegDst;         /* Register Destination */
  unsigned int RegWrite;         /* Write Register */
  unsigned int ALUSrc;         /* ALU Source */
  unsigned int MemRead;      /* Mem Read */
  unsigned int MemWrite;      /* Mem Write */ 
  unsigned int MemtoReg;      /* Memory to Register*/
  unsigned int ALUControl ;    /*4 bit ALU control */
  unsigned int Branch;         /* BEQ */
  unsigned int Jump;          /* Jump*/
} CS, *CS_ptr;

typedef struct RegisterStructure{ 
  int t0;         /* Register t0 */
  int t1;         /* Register t1 */
  int t2;         /* Register t2 */
  int t3;         /* Register t0 */
  int ReadData1;      /* Read Data 1 buffer */
  int ReadData2;      /* Read Data 2 buffer */ 
  int WriteReg; 
  unsigned int readReg1;   /* address of rs */
  unsigned int readReg2;   /* address of rt */
   /* WriteReg */
} RG, *RG_ptr;

typedef struct ALUStructure{
  int DataOut;
  unsigned int Zero;
} AS, *AS_ptr;

Затем файл Test.c включает эту библиотеку, объявляет переменные, которые используют эти структуры, а затем присваивает значения различным полям структуры.

Это Test.c файл:

#include "Test.h"
#include <stdio.h>

int main() {
 CS_ptr controlSignals;         // Line 5
 IF_ptr iFields;                // Line 6
 RG_ptr registers;              // Line 7 
 AS_ptr as;                     // Line 8

 controlSignals->RegDst = 0;    // Line 11
 //registers->t0 = 0;           // Line 12
 //iFields->op = 0;             // Line 13
 //as->DataOut = 0;             // Line 14

 printf("This is fine\n");
return 0;
}

Код выше работает нормально. Но как только я раскомментирую строку 12, возникает ошибка сегментации: Segmentation fault: 11. Я использовал valgrind, и это сообщение об ошибке:

==2002== Use of uninitialised value of size 8
==2002==    at 0x100000F5A: main (test.c:11)
==2002== 
==2002== Use of uninitialised value of size 8
==2002==    at 0x100000F64: main (test.c:12)
==2002== 
==2002== Invalid write of size 4
==2002==    at 0x100000F64: main (test.c:12)
==2002==  Address 0x0 is not stack'd, malloc'd or (recently) free'd

==2002== Process terminating with default action of signal 11 (SIGSEGV)
==2002==  Access not within mapped region at address 0x0
==2002==    at 0x100000F64: main (test.c:12)
==2002==  If you believe this happened as a result of a stack
==2002==  overflow in your program's main thread (unlikely but
==2002==  possible), you can try to increase the size of the
==2002==  main thread stack using the --main-stacksize= flag.
==2002==  The main thread stack size used in this run was 8388608.

Сначала я подумал, что это проблема унифицированных указателей, поэтому я инициализировал указатели на NULL. Но это ничего не исправило и даже создало больше ошибок сегментации. Поэтому я оставил их в покое.

Затем я попытался переместить вещи. Как ни странно, если я переместлю строку 7 наверх перед строкой 5 (чтобы сначала объявить RG_ptr) и раскомментирую строку 11, то будет выполнено registers->t0 = 0 и ошибка сегментации будет исправлена!

То же самое происходит с другими объявлениями указателей. Только когда объявление указателя в начале , выполняется соответствующее присвоение поля. Любые другие назначения полей, если они не закомментированы, вызывают ошибки сегментации.

Что происходит? Как можно решить эту проблему? Я ценю любую помощь!

Ответы [ 2 ]

0 голосов
/ 30 апреля 2018

Вы не выделили место для конструкций. А при разыменовании неинициализированного указателя вы получаете segfault, что вполне ожидаемо.

Кстати, новые указатели typedef.

RG * регистры; Регистры RG_ptr;

Второе объявление не похоже на указатель. Это потенциальный источник трудноуловимых ошибок. Используйте звезды для указателей.

0 голосов
/ 30 апреля 2018

Код проблемы:

RG_ptr registers;
registers->t0 = 0;

Обратите внимание, что RG_ptr - это указатель , и он никогда не инициализируется. Использование неинициализированного указателя является неопределенным поведением, и ваша программа падает.

Указатель NULL фактически не «инициализирован». Это просто делает нулевой указатель, и это указывает на неверную память. Вы не можете разыменовать этот указатель без сбоев либо. Обычно люди используют нулевые указатели для обозначения того, что «не назначено» или «не имеет значения», в отличие от неинициализированного, что означает, что указатель может содержать мусорные данные.

Вы должны инициализировать этот указатель, выделив память или указав на существующую структуру RG.

Например:

RG registers;
RG_ptr registers_pointer = &registers;

Или:

RG_ptr registers = malloc(sizeof(RG));

Помните, что если вы используете выделенную память, вы должны быть чрезвычайно дисциплинированными, чтобы гарантировать, что все выделения имеют соответствующие освобождения с free, иначе вы потеряете память.

...