lldb в xcode определяет, что целое число с именем I является комплексным числом

#c #xcode #lldb

#c #xcode #lldb

Вопрос:

У меня есть код C, в котором int I объявляется и инициализируется. При отладке в xcode, если я пытаюсь напечатать значение I , xcode пытается найти комплексное число:

 (lldb) p I
error: <lldb wrapper prefix>:43:31: expected unqualified-id
using $__lldb_local_vars::I;
                          ^
<user expression 3>:1760:11: expanded from here
#define I _Complex_I
      ^
<user expression 3>:7162:20: expanded from here
#define _Complex_I ( __extension__ 1.0iF )
  

Когда я пробую то же самое (останавливаясь на одной и той же точной строке в коде) в командной строке, без использования xcode, все работает нормально:

 (lldb) p I
(int) $0 = 56
  

Я загружаю следующие библиотеки:

 #include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
  

которое даже не должно включать комплексные числа, нет? У меня определенно нет макроса, который определяет I как комплексную переменную. Тот, который я запускаю в xcode, я компилирую с помощью инструментов xcode по умолчанию. Я использую то, которое я запускаю в командной строке gcc . В этом какая-то разница? Включает ли xcode больше библиотек, чем я прошу? Почему это происходит и как я могу это предотвратить?

Редактировать: я должен также добавить, что проводник переменных в xcode показывает значение I правильно, как целое число.

Комментарии:

1. I определено в <complex.h> и <complex.h> не включено по умолчанию. Если бы оно было включено, вы бы получили сообщение об ошибке при объявлении int I .

2. @user3386109 Я не включаю <complex.h> , хотя. И я не получаю сообщение об ошибке int I .

Ответ №1:

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

Обычно отладочная информация вообще не записывает макросы, поэтому вы не видите версию complex.h I , которую вы сами использовали в своем коде. Скорее, вы видите I макрос, потому что что-то вызвало импорт модуля Darwin в контекст выражения lldb.

Это может произойти двумя способами, либо потому, что вы явно попросили об этом, запустив:

 (lldb) expr @import Darwin
  

или потому, что вы создали эту программу с -fmodules и ваш код импортировал модуль Darwin, вставив инструкцию, подобную приведенной выше.

Выполнение этого вручную — обычный трюк, явно позволяющий сделать #defines из модуля видимым для анализатора выражений. Поскольку проблемы вызывает видимость макроса, вам придется прекратить это делать, если вы хотите, чтобы это выражение было успешным.

OTOH, если lldb делает это, потому что в отладочной информации записано, что какая-то часть вашего кода импортировала этот модуль, вы можете отключить поведение, поместив:

 settings set target.auto-import-clang-modules 0
  

в вашем ~/.lldbinit и перезапускает сеанс отладки.

КСТАТИ, p команда (или expression команда, для которой p является псевдонимом) оценивает текст, который вы предоставляете, как регулярное выражение, используя язык и в контексте текущего фрейма, с таким доступом к символам, определениям и тому подобному, который может предоставить lldb. Большинство пользователей также хотят иметь доступ к информации о классе, которая может быть не видна непосредственно в текущем фрейме, поэтому он стремится использовать как можно более широкую сеть для поиска символов и типов, чтобы включить это.

Это очень мощная функция, но, как вы видите, иногда желание предоставить такой широкий доступ к выражениям может привести к конфликту определений. И в любом случае, это намного мощнее, чем нужно только для просмотра локальной переменной.

у lldb есть другая команда: frame var (удобный псевдоним v ), которая печатает значения локальных переменных путем прямого доступа к памяти, на которую указывает отладочная информация, и представления ее с использованием типа из отладочной информации. Он поддерживает ограниченное подмножество C-подобного синтаксиса для ссылки на подэлемент; вы можете использовать * для разыменования, . или -> и, если переменная является массивом [0] и т.д…

Поэтому, если вам действительно не нужно запускать выражение (например, для доступа к вычисляемому свойству или вызова другой функции), v будет быстрее, и поскольку его реализация проще и непосредственнее, у него будет меньше шансов на незначительные сбои, чем p .

Если вы также хотите получить доступ к определению объекта некоторой локальной переменной ObjC или Swift, команда vo или frame var -O получит описание локальной переменной, которую она находит с помощью v метода.

Комментарии:

1. КСТАТИ, v or frame variable использует тот же механизм, что и представление локальных данных Xcode (и то же самое для VSCode, IIUC).

Ответ №2:

У меня определенно нет макроса, который определяет I как комплексную переменную.

Похоже, что lldb каким-то образом запутывается, это не проблема с вашим кодом, но без MRE трудно сказать.

Тот, который я запускаю в xcode, я компилирую с помощью инструментов xcode по умолчанию. То, которое я запускаю в командной строке, я использую gcc. В этом какая-то разница?

насколько я знаю, xcode по умолчанию использует «Apple clang» (старую пользовательскую версию) с libc . gcc совсем другое, и оно может даже не использовать libc .

Сказав это, поскольку xcode отображает переменную как целое число, а lldb — нет, похоже, что происходит что-то еще.

Включает ли xcode больше библиотек, чем я прошу?

Я так не думаю, учитывая, что программа работает, а Xcode показывает значение как целое число.

Почему это происходит и как я могу это предотвратить?

Трудно сказать, поскольку это инструмент с закрытым исходным кодом. Попробуйте создать MRE. Обычно это помогает отладить проблему и найти обходные пути.

Комментарии:

1. Спасибо, я постараюсь сделать MRE. Это относительно большой фрагмент кода, который я переместил в xcode для целей профилирования, поэтому это может занять время.

Ответ №3:

По определению комплексное число не определяется как простое int

Кроме того, как упоминалось, complex I определяется в <complex.h>:

Для построения комплексных чисел вам нужен способ указать мнимую часть числа. Для воображаемой константы с плавающей запятой нет стандартных обозначений. Вместо этого complex.h определяет два макроса, которые можно использовать для создания комплексных чисел.

 Macro: const float complex _Complex_I

    This macro is a representation of the complex number “0 1i”. Multiplying a real floating-point value by _Complex_I gives a complex number whose value is purely imaginary. You can use this to construct complex constants:

    3.0   4.0i = 3.0   4.0 * _Complex_I

    Note that _Complex_I * _Complex_I has the value -1, but the type of that value is complex. 

_Complex_I is a bit of a mouthful. complex.h also defines a shorter name for the same constant.

Macro: const float complex I

    This macro has exactly the same value as _Complex_I. Most of the time it is preferable. However, it causes problems if you want to use the identifier I for something else. You can safely write

    #include <complex.h>
    #undef I
  

Ссылка здесь на реализацию GNU

Включите этот файл заголовка (или аналогичный из вашей среды), и нет необходимости определять его самостоятельно

Комментарии:

1. Спасибо. Однако я не определяю его, и это странно.

2. @sodiumnitrate — Это странно. Но в вашем сообщении сообщение об ошибке является явным, по-видимому, жалуясь на <префикс оболочки lldb> … ожидаемый неквалифицированный идентификатор. Я посмотрел здесь, чтобы посмотреть, смогу ли я что-нибудь найти… Оно содержит эту строку, которая, по-видимому, является источником сообщения об ошибке: stream.Printf("using $__lldb_local_vars::%s;n", var_name.AsCString()); ( отсюда ) Больше ничего интересного.