__attribute__ на указателях функций - PullRequest
0 голосов
/ 13 июня 2018

Иногда я пишу обертки вокруг функций в стиле printf по разным причинам, и мне действительно нравится, когда clang сообщает мне о несоответствиях типов между спецификаторами формата и фактическими аргументами.Обратите внимание:

#include <stdarg.h>
#include <stdio.h>

static __attribute__((format(printf, 1, 2))) void log(const char *fmt, ...)
{
    va_list va;
    va_start(va, fmt);
    vprintf(fmt, va);
    va_end(va);
}

int main(void)
{
    log("%s", 42);
    return 0;
}

Если скомпилировано с -Wall, это аккуратно информирует меня об ошибке этого типа:

test.c:14:15: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
    log("%s", 42);
         ~~   ^~
         %d

Это очень хорошо работает для функций, но когда дело доходит до функции указатели , __attribute__((format(printf, 1, 2))), кажется, больше не действуют.Следующий код:

#include <stdarg.h>
#include <stdio.h>

typedef void (*log_t)(const char*, ...) __attribute__((format(printf, 1, 2)));

static __attribute__((format(printf, 1, 2))) void log(const char *fmt, ...)
{
    va_list va;
    va_start(va, fmt);
    vprintf(fmt, va);
    va_end(va);
}

int main(void)
{
    log_t func = &log;
    (*func)("%s", 42);
    return 0;
}

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

Есть ли способ с помощью clang указать атрибуты (или этот атрибут)для указателей на функции, чтобы он действительно был выбран во время компиляции?
Если это имеет значение, мой кланг сообщает о своей версии как: Apple LLVM version 9.0.0 (clang-900.0.39.2).

1 Ответ

0 голосов
/ 13 июня 2018

Помещение спецификатора атрибута в строку с объявлением указателя работает (т. Е. Приводит к предупреждению о несоответствующих аргументах)

log_t func __attribute__((format(printf, 1, 2))) = log; 

Так что я думаю, что вы застряли с использованием макроса, если целью являетсяминимизируйте ввод и сохраняйте код чистым.Как то так:

#define checkargs __attribute__((format(printf, 1, 2)))

typedef void (*log_t)(const char*, ...);

static checkargs void log(const char *fmt, ...)
{
    va_list va;
    va_start(va, fmt);
    vprintf(fmt, va);
    va_end(va);
}

int main(void)
{
    log_t checkargs func = log;
    func("%s", 42);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...