Избегайте конфликтов имен глобальных переменных / методов при использовании заголовков C в C ++ - PullRequest
2 голосов
/ 07 июля 2010

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

У меня возникла ситуациягде я занимаюсь разработкой на C ++ и использую strerror, и в результате я использую что-то похожее на

extern "C" {
#include <string.h>
}

(та же ситуация для #include <cstring>, кстати).Теперь есть функция, определенная в этом файле следующим образом: extern char *index (__const char *__s, int __c) Эта функция доставляет мне удовольствие, когда у меня изначально была конструкция, похожая на:

for (int index = 0; index != condition (); ++index) {
   // do something with buffer[index] here
}

log->write ("Final value of index: %d\n", index); // <- Ooops!!!

Но вместо того, чтобы получить ошибку компиляции, яполучить поддельный вывод.У меня установлены флаги компилятора (g ++) довольно высоко, и следующее не уловило это:

-W -Wall -Wextra -Werror -Wshadow -Wformat -pedantic -ansi

Я также не могу использовать трюк #undef, как в <cstring>, потому чтоэто не макрос.

Мой вопрос заключается в том, сталкивались ли другие с этой же проблемой и как ее лучше решить?В идеале я хотел бы услышать о некоторых неясных функциях g ++, таких как -use-the-force-luke=...;)

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

РЕДАКТИРОВАТЬ:

Из-за ответа Джеймса Керрана я думаю, что я должен немного уточнить.Я не смотрю на то, почему этого не должно происходить.Я понимаю, что при отсутствии локальных переменных область видимости расширяется.Что меня удивляет , так это то, что я не могу установить флаг, предупреждающий об этом.Я бы подумал, что -Wshadow поймает его, так как он перехватывает затенение переменной / метода в области видимости класса, но я отступаю.

Меня интересует способ получения уведомления о том, что локальное имяв конфликте с нелокальной областью действия.Есть упоминание, что я бы поймал эту конкретную ошибку, если бы использовал потоковые операции вместо вызовов с переменным числом.Правда, но даже следующее не выдаст предупреждений / ошибок с g++ (GCC) 4.1.1 20070105 (Red Hat 4.1.1-51) и следующими флагами -W -Wall -Wextra -Werror -Wshadow -ansi -pedantic.

#include <iostream>
#include <cstring>

int main () {
        int index = 42;
        std::cerr << index << std::endl;
        return 0;
}

Это любопытно для меня.

Ответы [ 4 ]

7 голосов
/ 07 июля 2010

Во-первых, похоже, что вы используете переменный список аргументов в стиле printf, что приводит к немедленной потере безопасности типов. Вероятно, вам следует избегать такого дизайна в C ++.

Если вам нужно сделать это, то вы можете рассмотреть возможность объявления функции, чтобы сообщить gcc, что это функция, похожая на printf, и она выдаст вам предупреждения, если ваш список аргументов не соответствует вашей строке формата, как это происходит для стандартных *printf функций.

* 1006 Е.Г. *

void write(const char* f, ...) __attribute__((format (printf, 2, 3)));
2 голосов
/ 07 июля 2010

Это всего лишь результат правил области видимости C ++ - следующий код подходит:

int f() {
    return 42;
}


int main() {
    for ( int f = 0; f < 10; f++ ) {
    }
}

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

0 голосов
/ 07 июля 2010

Давайте посмотрим на это шаг за шагом;

  • Вы включаете заголовок, который определяет идентификатор, о котором вы не знаете.(неизбежно)
  • Вы используете тот же идентификатор в качестве другого типа в своем коде (легально и, по-видимому, приемлемо для вас)
  • Вы случайно используете эту переменную вне ее области действия (неудобно, но случайно)
  • Вместо того, чтобы сообщать об ошибке выше, компилятор использует идентификатор, определенный во внешней области видимости.(именно то, что он должен делать в соответствии со Стандартом).

Итак, на самом деле возникает вопрос: «От чего вы ожидали этого?»«и« Как мы можем реализовать это, не нарушая много существующего кода? »

На самом деле, реальный вопрос:« Почему у вас возникает эта проблема с <cstring>, который оборачивает функции в пространстве имен std? »- означает, что функция на самом деле будет называться std :: index (). Вы не полностью изменили это, добавив:

using namespace std;
0 голосов
/ 07 июля 2010

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

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