2010-05-06 4 views
4

ПочемуC массив инициализации

static char *opcode_str[] = { "DATA" 
          , "DATA_REQUEST_ACK" 
          , "ACK_TIMER_EXPIRED" 
          , "ACK_UNEXPECTED_SEQ" 
          , "ACK_AS_REQUESTED" 
          } ; 

работы, но

static char **opcode_str = { "DATA" 
          , "DATA_REQUEST_ACK" 
          , "ACK_TIMER_EXPIRED" 
          , "ACK_UNEXPECTED_SEQ" 
          , "ACK_AS_REQUESTED" 
          } ; 

терпит неудачу с SEGV когда opcode_str [0] printf'd?

Я думаю, это потому, что второй листинг не выделил память для пятиэлементного массива указателей, но мне нужно более полное объяснение.

Всего наилучшего,

Chris.

ответ

10

Это правильно. Вы по существу пытаетесь назначить массив указателю. GCC 4.4.1 предупреждает об этом по умолчанию:

opcode_str.c:4: warning: initialization from incompatible pointer type 
opcode_str.c:5: warning: excess elements in scalar initializer 

Он повторяет лишние элементы предупреждения в 4 раза, так как вы в основном положить 5 указателей, где только один будет соответствовать. Вы можете использовать gcc -Werror, чтобы заставить все предупреждения быть ошибками.

Вы можете сделать:

static char **opcode_str = malloc(sizeof(char *) * 5); 
opcode_str[0] = "DATA"; 
opcode_str[1] = "DATA_REQUEST_ACK"; 
opcode_str[2] = "ACK_TIMER_EXPIRED"; 
opcode_str[3] = "ACK_UNEXPECTED_SEQ"; 
opcode_str[4] = "ACK_AS_REQUESTED"; 

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

Но я думаю, что opcode_str содержит указатель на DATA. Поэтому (предположим, 32-битный) он попытается интерпретировать первые четыре байта в opcode_str ('D', 'A', 'T', 'A') как четыре байта char *.

+0

Спасибо. Почему это не прерывается во время компиляции или когда указатель инициализируется? – fadedbee

+2

@chrisdew это неопределенное поведение, чтобы нарушить семантическое правило в C. Правило, которое вы нарушаете, - это * Инициализатор для скаляра должен быть единственным выражением, необязательно заключенным в фигурные скобки. * У вас есть несколько выражений, заключенных в фигурные скобки. –

+1

Вот и все, я позволю прокрутить предупреждение прямо со своего экрана. Doh! Теперь я вижу, что я устанавливаю указатель char ** на значение указателя char * на «DATA». Затем «DATA» оценивалась так, как если бы эти четыре/восемь байтов содержали указатель, и это вызывало segfault. – fadedbee