2016-12-20 2 views
-3

У меня есть переменная функция в C для записи в файл журнала, но как только она вызывается, она дает ошибку сегментации в заголовке.C - Функция Variadic компилируется, но дает ошибку сегментации

В основном процессе, вызов имеет следующий формат:

mqbLog("LOG_INFORMATION",0,0,"Connect",0,"","Parameter received"); 

и функция определяется следующим образом:

void mqbLog(char *type, 
      int numContext, 
      double sec, 
      char *service, 
      int sizeData, 
      char *data, 
      char *fmt, 
      ... 
      ) 
{ 
    //write the log in the archive 
} 

Компилируется OK. Когда я отладки процесса, вызов функции mqbLog делается, и это дает мне ошибку сегментации в открывающей скобки функции, так что я могу спросить о значениях функции:

(gdb) p type 
$1 = 0x40205e "LOG_INFORMATION" 
(gdb) p numContext 
$2 = 0 
(gdb) p sec 
$3 = 0 
(gdb) p service 
$4 = 0x0 
(gdb) p sizeData 
$5 = 4202649 
(gdb) p data 
$6 = 0x0 

Любые идеи будут с благодарностью получил.

+0

У вас есть ошибка в реализации этой функции. Я предлагаю начать с чтения соответствующих руководств около ''. –

+5

Дайте нам достаточно кода для репликации ошибки. –

+4

Где декларация функции? Ваш вызов основан на неявном преобразовании '0' в' 0.0' в рамках прототипа. Опущение прототипа, где вызвана функция, является по своей сути неопределенным поведением; вы должны * всегда * иметь прототип в области действия до вызова вариационной функции. Ваша функция сбой, но вы не показали, как вы реализовали эту функцию. Как вы ожидаете, что мы поможем вам отладить его? Есть много вещей, которые вы могли бы сделать неправильно; многие из них могут привести к краху. Включите MCVE ([MCVE]), который воспроизводит авария. –

ответ

2

Основываясь на выходе gdb, похоже, что у вызывающего не было прототипа функции, которую он вызывал. Как заметил @JonathanLeffler, вы написали 0 вместо 0.0, поэтому он передает целое число, где вызываемый ожидает double.


Судя по значению указателя, это, вероятно, на x86-64 Linux с System V вызовов, где регистр назначается для арг определяются причем, например, третий целое число arg. (См. Вики для документов ABI/call конвенций).

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


В этом случае абонент помещает "Connect" (адрес) в RCX, потому что это четвёртое число/указатель агд с этой неявной декларации.

Вызывающий ищет значение service в RDX, потому что его третье целое число/указатель arg вызывающего.

sec является 0,0 в вызываемой, по-видимому, случайно. Это просто использование того, что было в XMM0. Или, может быть, возможно неинициализированное пространство стека, поскольку вызывающий абонент установил бы AL=0, чтобы указать, что в регистры не были переданы никакие аргументы FP (необходимые только для вариационных функций). Примечание al = количество аргументов в регистре fp содержит фиксированные невариантные аргументы, когда прототип доступен. Компиляция вашего звонка с номером. Доступный прототип включает mov eax, 1 до call. См. Источник + asm для компиляции с/без прототипа on the Godbolt compiler explorer.

В других вызовах (например, -m32 с стеком аргом), то сломается, по крайней мере плохо, потому что эти аргументы будут переданы в стеке, но int и double имеют разные размеры.


Дать 0.0 для арг FP сделает неявное объявление соответствует определению.Но не делайте этого, это еще страшная идея вызывать незаявленные функции. Используйте -Wall, чтобы компилятор сообщал вам, когда ваш код плохо работает.

Вы можете по-прежнему крутиться; кто знает, какие еще ошибки у вас есть в коде, который не отображается?


Когда ваши аварии кода, вы должны смотреть на инструкции ассемблерный он разбился на выяснить, какой указатель плохо - например, запустить disas в gdb. Даже если вы не понимаете это самостоятельно, в том числе, что в вопросе отладки-справки (наряду с значениями регистра) может многое помочь.

+0

Спасибо, Питер! Я внес изменения, которые вы указали, и работает отлично (номер_дублицы (duh), объявление функции). Извините, если я не мог ответить раньше, вчера был хаотичный день D: –