int const main(int const argc, char const* const* const argv)
int const main(int const argc, char const* const* const argv)
#1267777 писать так:
void print(const char *const what) __attribute__((nonnull(1)));
void print(const char *const what)
{
if (what)
printf("%s\n", what);
}
это требует чтобы аргумент 1 был не 0, но, к сожалению, такие вещи как
char *b = NULL;
print(b);
__attribute__((nonnull())) уже не ловит :(
оказывается можно вместо void print(const char *const what) __attribute__((nonnull(1)));
void print(const char *const what)
{
if (what)
printf("%s\n", what);
}
это требует чтобы аргумент 1 был не 0, но, к сожалению, такие вещи как
char *b = NULL;
print(b);
__attribute__((nonnull())) уже не ловит :(
#include <sys/cdefs.h>
#include <stdio.h>
__errordecl (check_null, "NULL argument!");
void print(const char *const what)
{
const __uint64_t t = (__uint64_t)what;
if (__builtin_constant_p(t) && (what == NULL))
{
check_null();
return;
}
printf("%s\n", what);
}
print("text"); // всё OK
print(NULL); // не скомпилируется
warning: ignoring return value of ‘int chown(const char*, __uid_t, __gid_t)’, declared with attribute warn_unused_result
Типы макросов в Си:
1) подстановки
2) процедуры
3) функции
1) подстановки используются просто для подстановки значений, например:
#define TMP_PATH "/tmp"
пример импользования в коде:
char file[] = TMP_PATH"/file.txt";
2) процедуры используются для выполнения определенных действий, например:
#define LOG(ARGS...) \
do { \
printf("log: "); \
printf(ARGS); \
printf("\n"); \
} while (0)
пример: LOG("%s, %s!", "Hello", "world");
3) функции возвращают значения, да, макросы умеют возвращать значения, например:
#define CREATE_COPY(value) \
({ \
void *ret = malloc(sizeof(value)); \
memcpy(ret, &value, sizeof(value)); \
ret; \
})
процедуры и функции заклюючаются в разные скобки:
процедуры: do { ... } while(0) — void-выражения и требуют вконце ;
функции: ({ ... }) — возвращают значение выражения, указанное последним.