Есть ли какие-либо гарантии в отношении соответствия директив __LINE__? - PullRequest
11 голосов
/ 05 июня 2019

GCC 9 недавно изменил поведение директивы __LINE__ в некоторых случаях.Программа ниже иллюстрирует изменение:

#include <stdio.h>
#define expand() __LINE__
int main() {
  printf("%d\n",expand(
                ));
  return 0;
}

Поскольку макрос expand() (который расширяется до __LINE__) занимает более одной строки, GCC до 8,3 (и Clang до 8,0) учитывает числопоследней строки расширения, печать 5.Но GCC 9 учитывает строку first и печатает 4.

(ссылка Godbolt: https://godbolt.org/z/3Nk2al)

Стандарт C11 не очень точен в отношении точного поведения __LINE__, кроме:

6.10.8 Предопределенные имена макросов

Значения предопределенных макросов, перечисленные в следующих подпунктах (кроме __FILE____LINE__) остаются неизменными на протяжении всей единицы перевода.

(...)

6.8.10.1 Обязательные макросы

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

(...)

__LINE__ Предполагаемый номер строки (в текущем исходном файле) текущей строки источника (целочисленная константа).

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

дляНапример, можно ли утверждать, что предполагаемый номер строки текущей строки источника должен быть стабильным до тех пор, пока сам источник не изменился?

1 Ответ

1 голос
/ 05 июня 2019

Хотя общий случай нахождения номера строки по конкретной инструкции сложен, т. Е. GDB пытается найти номер строки из некоторого кода, который вылетел, инструкция printf __LINE__ относительно прямолинейна, так как компилятор генерируетчисло как статическое для определенного местоположения.

Сам стандарт C11 просто говорит, что номер строки не должен изменяться, пока вы находитесь в макросе, то есть __LINE__ должен отражать, где вы находитесь в программе послемакрос был расширен, а не строка кода, в которой расположен макрос.Это позволяет вам делать такие вещи, как предоставление номера строки вызываемой функции, создав макрос, который напечатал номер строки и затем вызвал вашу функцию.Например:

#define f(x) ({ printf("called f(x) at line=%d\n", __LINE__); f__real(x); })

Что касается точного представленного номера строки, он зависит от компилятора и не является частью какого-либо стандарта.Т.е. ваш пример может быть переписан как:

int main() {
  printf("%d\n", 
         __LINE__);
}

, и в этом случае допустимый ответ может быть 2 или 3.

Если вы пытаетесь определить номер строки динамически, то естьпредоставляется через системные библиотеки отслеживания.т.е. backtrace () в Linux.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...