Есть ли предупреждение GCC для использования символов из библиотеки C не через пространство имен std?

Рассмотрим следующий (глючный) код C ++:

#include <cmath>
#include <cstdlib>

#include <iostream>

int main() {
if (abs(-0.75) != 0.75) {
std::cout << "Math is broken!\n";
return 1;
} else {
return 0;
}
}

Этот код глючит, потому что он вызывает abs (имея в виду ::abs) вместо std::abs, В зависимости от реализации, ::abs может не существовать, или это может быть C absили это может быть набор перегрузки, включая версию для double, лайк std::abs является.

С Clang в Linux, по крайней мере, в моей среде, это второй вариант: C abs, Это вызывает два предупреждения, даже без явного включения:

<source>:7:9: warning: using integer absolute value function 'abs' when argument is of floating point type [-Wabsolute-value]
if (abs(-0.75) != 0.75) {
^
<source>:7:9: note: use function 'std::abs' instead
if (abs(-0.75) != 0.75) {
^~~
std::abs
<source>:7:13: warning: implicit conversion from 'double' to 'int' changes value from -0.75 to 0 [-Wliteral-conversion]
if (abs(-0.75) != 0.75) {
~~~ ^~~~~

В GCC я получаю разные результаты в разных средах, и я еще не выяснил, какие детали среды актуальны. Однако более распространенным вариантом является также то, что он вызывает C abs функция. Однако даже при -Wall -Wextra -pedantic, это не дает никаких предупреждений. Я могу заставить предупреждение с -Wfloat-conversion, но это дает слишком много ложных срабатываний для остальной части моей кодовой базы (что, возможно, мне следует исправить, но это другая проблема):

<source>: In function 'int main()':
<source>:7:18: warning: conversion to 'int' alters 'double' constant value [-Wfloat-conversion]
if (abs(-0.75) != 0.75) {
^

Есть ли способ получить предупреждение всякий раз, когда я использую функцию библиотеки через глобальное пространство имен, когда версия в пространстве имен std такое перегрузка?

14

Решение

Вот решение. Я не доволен этим, но это может сработать для вас

namespace DontUseGlobalNameSpace {
// put all std functions here you want to catch
int abs(int x);
}
using namespace DontUseGlobalNameSpace;

Теперь, если вы используете abs() без уточнения вы получите ошибку «символ неоднозначен».

3

Другие решения

Это будет сложно. GCC <cmath> заголовок просто включает <math.h>, #undefs его макросы (на всякий случай) и определяет функции C ++ как встроенные функции, которые используют некоторые идентификаторы из <math.h>, Большинство функций на самом деле относятся к встроенным компиляторам: например, std::abs определяется с помощью __builtin_abs и не ::abs,

поскольку <cmath> и ваша «глючная программа» находится в одном и том же модуле перевода, трудно понять, как видимость может быть разделена: как встроенные функции <cmath> может быть разрешено использовать <math.h> вещи, в то время как ваш код не будет.

Ну, есть следующий путь: <cmath> придется переписать, чтобы предоставить свои собственные локальные объявления для всего, что ему нужно от <math.h> и на самом деле не включать этот заголовок.

Вместо этого мы можем подготовить заголовочный файл, который повторно объявляет функции, которые нам не нужны, с __attribute__ ((deprecated)):

// put the following and lots of others like it in a header:
extern "C" int abs(int) throw () __attribute__ ((deprecated));
#include <cmath>
#include <cstdlib>

#include <iostream>

int main() {
if (abs(-0.75) != 0.75) {
std::cout << "Math is broken!\n";
return 1;
} else {
return 0;
}
}

Сейчас:

$ g++ -Wall  buggy.cc
buggy.cc: In function ‘int main()’:
buggy.cc:9:7: warning: ‘int abs(int)’ is deprecated [-Wdeprecated-declarations]
if (abs(-0.75) != 0.75) {
^~~
In file included from /usr/include/c++/6/cstdlib:75:0,
from buggy.cc:4:
/usr/include/stdlib.h:735:12: note: declared here
extern int abs (int __x) __THROW __attribute__ ((__const__)) __wur;
^~~
buggy.cc:9:16: warning: ‘int abs(int)’ is deprecated [-Wdeprecated-declarations]
if (abs(-0.75) != 0.75) {
^
In file included from /usr/include/c++/6/cstdlib:75:0,
from buggy.cc:4:
/usr/include/stdlib.h:735:12: note: declared here
extern int abs (int __x) __THROW __attribute__ ((__const__)) __wur;
^~~

Предупреждение компоновщика было бы проще. Я попробовал это; проблема в том, что эта тестовая программа на самом деле не генерирует внешнюю ссылку на abs (хотя есть #undef abs в <cmath>). Вызов встраивается, и поэтому уклоняется от предупреждения компоновщика.

Следуя комментарию DanielH, я придумал уловку, которая позволяет std::abs но блоки abs:

#include <cmath>
#include <cstdlib>
#include <iostream>

namespace proj {
// shadowing declaration
int abs(int) __attribute__ ((deprecated));

int fun() {
if (abs(-0.75) != 0.75) {
std::cout << "Math is broken!\n";
return 1;
} else {
return std::abs(-1); // must be allowed
}
}
}

int main() {
return proj::fun();
}

Простые пространства имен могут быть использованы. Кроме того, нам не нужны deprecated атрибутов; мы можем просто объявить abs в качестве несовместимой функции или нефункционального идентификатора целиком:

#include <cmath>
#include <cstdlib>
#include <iostream>

namespace proj {
// shadowing declaration
class abs;

int fun() {
if (abs(-0.75) != 0.75) {
std::cout << "Math is broken!\n";
return 1;
} else {
return std::abs(-1); // must be allowed
}
}
}

int main() {
return proj::fun();
}

$ g++ -std=c++98 -Wall  buggy.cc -o buggy
buggy.cc: In function ‘int proj::fun()’:
buggy.cc:10:18: error: invalid use of incomplete type ‘class proj::abs’
if (abs(-0.75) != 0.75) {
^
buggy.cc:7:9: note: forward declaration of ‘class proj::abs’
class abs;
^~~
buggy.cc:16:3: warning: control reaches end of non-void function [-Wreturn-type]
}
^

При таком подходе нам просто нужен список имен и помещаем их в некоторый заголовок, который обеспечивает это:

int abs, fabs, ...; // shadow all of these as non-functions

я использовал -stdc++98 в g++ командной строки, чтобы подчеркнуть, что это просто старая школа C ++ namespace семантика на работе.

2

Этот код позволит вам определить, существует ли ловушка в конкретной среде:

double (*)(double) = &::abs; // fails if you haven't included math.h, possibly via cmath

Но это не поможет вам определить места, в которые вы попали в ловушку.

0
По вопросам рекламы [email protected]