Как сбой во время компиляции, если условие является ложным в коде C? [Дубликат]

Вы можете использовать метод dataframe notnull или инвертировать isnull или numpy.isnan :

In [332]: df[df.EPS.notnull()]
Out[332]:
   STK_ID  RPT_Date  STK_ID.1  EPS  cash
2  600016  20111231    600016  4.3   NaN
4  601939  20111231    601939  2.5   NaN


In [334]: df[~df.EPS.isnull()]
Out[334]:
   STK_ID  RPT_Date  STK_ID.1  EPS  cash
2  600016  20111231    600016  4.3   NaN
4  601939  20111231    601939  2.5   NaN


In [347]: df[~np.isnan(df.EPS)]
Out[347]:
   STK_ID  RPT_Date  STK_ID.1  EPS  cash
2  600016  20111231    600016  4.3   NaN
4  601939  20111231    601939  2.5   NaN

63
задан Matt Joiner 2 August 2010 в 07:32
поделиться

10 ответов

Стандарт C11 добавляет ключевое слово _Static_assert.

Это реализовано с gcc-4.6 :

_Static_assert (0, "assert1"); /* { dg-error "static assertion failed: \"assert1\"" } */

Первый слот должен быть интегральное постоянное выражение. Второй слот - это строковый литерал, который может быть длинным (_Static_assert(0, L"assertion of doom!")).

Следует отметить, что это также реализовано в последних версиях clang.

58
ответ дан L29Ah 21 August 2018 в 07:35
поделиться
  • 1
    [... кажется, реализуется gcc, clang ...] Вы можете быть более assertive , что ;-) _Static_assert является частью стандарта C11 и любой компилятор, поддерживающий C11, получит его. – P.P. 12 October 2014 в 21:30
  • 2
    Может ли это использоваться в области файлов (вне любой функции)? Потому что я получаю error: expected declaration specifiers or '...' before 'sizeof' для строки static_assert( sizeof(int) == sizeof(long int), "Error!); (кстати, я использую C не C ++) – user10607 21 November 2014 в 07:25
  • 3
    @ user10607 Я удивлен, что это не работает. Подождите, вам не хватает цитаты в конце строки ошибки. Вставьте это и вернитесь. Это работает для меня на gcc-4.9: _Static_assert( sizeof(int) == sizeof(long int), "Error!"); На моем macine я получаю ошибку. – emsr 21 November 2014 в 15:04
  • 4
    У меня есть gcc 4.8.2 на Ubuntu. Пропущенная цитата была оговоркой о комментариях (у меня было это в коде). Это первая строка в файле после включения нескольких заголовков. Компилятор дает мне две одинаковые ошибки: error: expected declaration specifiers or '...' before 'sizeof' AND error: expected declaration specifiers or '...' before string constant (он ссылается на строку "Error!") (также: я компилирую с -std = c11. При помещении объявления внутри функции все работает хорошо ( терпит неудачу и преуспевает, как ожидалось)) – user10607 21 November 2014 в 15:20
  • 5
    @ user10607 Мне также пришлось указать -std = gnu11 в командной строке. Я очень удивлен, что разница между 4.8 и 4.8 будет разной. У меня есть источник только с одной строкой. Я также использовал стандарт C _Static_assert, а не C ++ ish static_assert. Вам нужно `#include & lt; assert.h & gt; для получения макроса static_assert. – emsr 21 November 2014 в 15:43

cl

Я знаю, что вопрос явно упоминает gcc, но только для полноты здесь есть настройка для компиляторов Microsoft.

Использование массива с отрицательным размером typedef не убеждает cl , чтобы выплюнуть приличную ошибку. Он просто говорит error C2118: negative subscript. В этом отношении лучше всего подходит битовая область с нулевой шириной. Поскольку это подразумевает типизацию структуры, нам действительно нужно использовать уникальные имена типов. __LINE__ не разрезает горчицу; возможно иметь COMPILE_TIME_ASSERT() в той же строке в заголовке и исходном файле, и ваш компилятор сломается. __COUNTER__ приходит на помощь (и он был в gcc с 4.3).

#define CTASTR2(pre,post) pre ## post
#define CTASTR(pre,post) CTASTR2(pre,post)
#define STATIC_ASSERT(cond,msg) \
    typedef struct { int CTASTR(static_assertion_failed_,msg) : !!(cond); } \
        CTASTR(static_assertion_failed_,__COUNTER__)

Теперь

STATIC_ASSERT(sizeof(long)==7, use_another_compiler_luke)

в cl дает:

< blockquote>

error C2149: 'static_assertion_failed_use_another_compiler_luke': имя битового поля не может иметь нулевую ширину

Gcc также дает понятное сообщение:

error: zero width для бит-поля 'static_assertion_failed_use_another_compiler_luke'

11
ответ дан bobbogo 21 August 2018 в 07:35
поделиться

Если вы используете макрос STATIC_ASSERT () с __LINE__, можно избежать столкновений строк между записью в файле .c и другой записью в файле заголовка, включив __INCLUDE_LEVEL__.

Например:

/* Trickery to create a unique variable name */
#define BOOST_JOIN( X, Y )      BOOST_DO_JOIN( X, Y )
#define BOOST_DO_JOIN( X, Y )   BOOST_DO_JOIN2( X, Y )
#define BOOST_DO_JOIN2( X, Y )  X##Y
#define STATIC_ASSERT(x)        typedef char \
        BOOST_JOIN( BOOST_JOIN(level_,__INCLUDE_LEVEL__), \
                    BOOST_JOIN(_assert_on_line_,__LINE__) ) [(x) ? 1 : -1]
2
ответ дан BrentNZ 21 August 2018 в 07:35
поделиться

Я бы не рекомендовал использовать решение с помощью typedef:

#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1]

Объявление массива с ключевым словом typedef НЕ гарантируется, что оно будет оцениваться во время компиляции. Например, следующий код в области блока будет компилироваться:

int invalid_value = 0;
STATIC_ASSERT(invalid_value, this_should_fail_at_compile_time_but_will_not);

Я бы рекомендовал это вместо этого (на C99):

#define STATIC_ASSERT(COND,MSG) static int static_assertion_##MSG[(COND)?1:-1]

Из-за ключевого слова static массив будет определен во время компиляции. Обратите внимание, что это утверждение будет работать только с COND, которые оцениваются во время компиляции. Он не будет работать (например, сбой компиляции) с условиями, основанными на значениях в памяти, таких как значения, присвоенные переменным.

0
ответ дан FredFredFredFred 21 August 2018 в 07:35
поделиться

Для тех из вас, кто хочет что-то действительно базовое и портативное, но не имеет доступа к функциям C ++ 11, я написал только что. Обычно используйте STATIC_ASSERT (вы можете записать его дважды в той же функции, если хотите) и использовать GLOBAL_STATIC_ASSERT вне функций с уникальной фразой в качестве первого параметра.

#if defined(static_assert)
#   define STATIC_ASSERT static_assert
#   define GLOBAL_STATIC_ASSERT(a, b, c) static_assert(b, c)
#else
#   define STATIC_ASSERT(pred, explanation); {char assert[1/(pred)];(void)assert;}
#   define GLOBAL_STATIC_ASSERT(unique, pred, explanation); namespace ASSERTATION {char unique[1/(pred)];}
#endif

GLOBAL_STATIC_ASSERT(first, 1, "Hi");
GLOBAL_STATIC_ASSERT(second, 1, "Hi");

int main(int c, char** v) {
    (void)c; (void)v;
    STATIC_ASSERT(1 > 0, "yo");
    STATIC_ASSERT(1 > 0, "yo");
//    STATIC_ASSERT(1 > 2, "yo"); //would compile until you uncomment this one
    return 0;
}

Объяснение : Сначала он проверяет, есть ли у вас реальное утверждение, которое вы, безусловно, захотите использовать, если оно доступно. Если вы этого не сделаете, вы получите свой pred текст и разделите его самостоятельно. Это делает две вещи. Если он равен нулю, id est, утверждение не сработало, это приведет к делению на нулевую ошибку (арифметика вынуждена, потому что она пытается объявить массив). Если он не равен нулю, он нормализует размер массива до 1. Поэтому, если это утверждение прошло, вы бы не захотели, чтобы он сбой в любом случае, потому что ваш предикат был оценен как -1 (недействителен) или был 232442 (массовая потеря пространства, IDK, если бы он был оптимизирован). Для STATIC_ASSERT он завернут в фигурные скобки, что делает его блоком, который использует переменную assert, что означает, что вы можете писать ее много раз. Он также переключает его на void, что является известным способом избавиться от предупреждений unused variable. Для GLOBAL_STATIC_ASSERT вместо того, чтобы быть в блоке кода, он генерирует пространство имен. Пространства имен разрешены вне функций. Идентификатор unique необходим, чтобы остановить любые конфликтующие определения, если вы используете этот один более одного раза.


Работал для меня на GCC и VS'12 C ++

0
ответ дан Hashbrown 21 August 2018 в 07:35
поделиться

Это работало для какого-то старого gcc. Извините, что я забыл, какая версия была:

#define _cat(x, y) x##y

#define _sassert(exp, ln)\
extern char _cat(SASSERT_, ln)[1]; \
extern char _cat(SASSERT_, ln)[exp ? 1 : 2]

#define sassert(exp) _sassert((exp), __LINE__)

//
sassert(1 == 2);

//
#148 declaration is incompatible with "char SASSERT_134[1]" (declared at line 134)  main.c  /test/source/controller line 134    C/C++ Problem
0
ответ дан jay 21 August 2018 в 07:35
поделиться

Классический способ использования массива:

char int_is_4_bytes_assertion[sizeof(int) == 4 ? 1 : -1];

Это работает, потому что если утверждение истинно, массив имеет размер 1, и он действителен, но если он ложный, размер -1 дает ошибка компиляции.

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

1
ответ дан Paolo.Bolzoni 21 August 2018 в 07:35
поделиться

Из Wikipedia :

#define COMPILE_TIME_ASSERT(pred) switch(0){case 0:case pred:;}

COMPILE_TIME_ASSERT( BOOLEAN CONDITION );
4
ответ дан Tyler 21 August 2018 в 07:35
поделиться
  • 1
    Он не работает вне функций. – Matt Joiner 2 August 2010 в 07:42
  • 2
    Было бы лучше, если бы вы связались с истинным источником: jaggersoft.com/pubs/CVu11_3.html – Matt Joiner 2 August 2010 в 07:43
  • 3
    Он не работает в gcc 4.6 - он говорит, что метка case не сводится к целочисленной константе ". Это имеет смысл. – Liosan 12 December 2013 в 10:47
  • 4
    вы оба, вероятно, сейчас переехали в waaay, но я закончил писать свои собственные (см. мой ответ ). Я использовал вашу ссылку @MattJoiner, чтобы помочь мне – Hashbrown 16 September 2014 в 17:51
  • 5
    И если вы можете быть обеспокоены, дайте мне знать, если это сработает для вас, @ Liosan. Я только начал вникать в C ++, поэтому я опоздал на вечеринку – Hashbrown 16 September 2014 в 17:51

Это работает в функциональной и нефункционной области (но не внутри структур, союзов).

#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1]

STATIC_ASSERT(1,this_should_be_true); 

int main()
{
 STATIC_ASSERT(1,this_should_be_true); 
}
  1. Если утверждение времени компиляции невозможно сопоставить, то GCC sas.c:4: error: size of array ‘static_assertion_this_should_be_true’ is negative
  2. генерирует почти понятное сообщение. Макрос может или должен быть изменен на сгенерируйте уникальное имя для typedef (т. е. concatenate __LINE__ в конце имени static_assert_...)
  3. Вместо тройного, это также можно использовать #define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[2*(!!(COND))-1], который, по-видимому, работает даже на Rusty oldc cc65 (для 6502 процессора).

ОБНОВЛЕНИЕ: Для полноты, вот версия с __LINE__

#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(!!(COND))*2-1]
// token pasting madness:
#define COMPILE_TIME_ASSERT3(X,L) STATIC_ASSERT(X,static_assertion_at_line_##L)
#define COMPILE_TIME_ASSERT2(X,L) COMPILE_TIME_ASSERT3(X,L)
#define COMPILE_TIME_ASSERT(X)    COMPILE_TIME_ASSERT2(X,__LINE__)

COMPILE_TIME_ASSERT(sizeof(long)==8); 
int main()
{
    COMPILE_TIME_ASSERT(sizeof(int)==4); 
}

UPDATE2: GCC Код

GCC 4.3 (я думаю) представил атрибуты функции «ошибка» и «предупреждение». Если вызов функции с этим атрибутом не может быть устранен посредством устранения мертвого кода (или других мер), то генерируется ошибка или предупреждение. Это можно использовать для утверждения времени компиляции с описаниями ошибок, определенных пользователем. Остается определить, как они могут использоваться в области пространства имен, не прибегая к фиктивной функции:

#define CTC(X) ({ extern int __attribute__((error("assertion failure: '" #X "' not true"))) compile_time_check(); ((X)?0:compile_time_check()),0; })

// never to be called.    
static void my_constraints()
{
CTC(sizeof(long)==8); 
CTC(sizeof(int)==4); 
}

int main()
{
}

И вот как это выглядит:

$ gcc-mp-4.5 -m32 sas.c 
sas.c: In function 'myc':
sas.c:7:1: error: call to 'compile_time_check' declared with attribute error: assertion failure: `sizeof(int)==4` not true
75
ответ дан ulidtko 21 August 2018 в 07:35
поделиться
  • 1
    В Visual Studio он просто говорит «Отрицательный индекс», не упоминая имя переменной ... – szx 25 April 2012 в 16:20
  • 2
    Nordic Mainframe - вариант 3 в вашем ответе не работает на clang. – Elazar 17 April 2013 в 08:19
  • 3
    Что касается последнего (GCC 4.3 + -специфического) решения: это очень мощно, так как он может проверять все, что может определить оптимизатор, но он терпит неудачу, если оптимизация не включена. Тем не менее, минимальный уровень оптимизации (-Og) может быть достаточно для того, чтобы это работало и не должно мешать отладке. Можно подумать о том, чтобы статические утверждать не-op или runtime assert, если __OPTIMIZE____GNUC__) не определено. – Søren Løvborg 17 September 2014 в 17:39
  • 4
    В фрагменте кода с версией LINE (UPDATE: для полноты, вот версия с `LINE), при компиляции, это ошибки в строке (STATIC_ASSERT (X, static_assertion_at_line _ ## L)), которые можно исправить, добавив еще одну как показано ниже: #define COMPILE_TIME_ASSERT4 (X, L) static_assert (X, # L); #define COMPILE_TIME_ASSERT3 (X, L) COMPILE_TIME_ASSERT3 (X, "Утверждение при: ## L"); – sundar 27 May 2016 в 11:51
  • 5
    Я использую нечто похожее на версию __LINE__ в gcc 4.1.1 ... со случайным раздражением, когда два разных заголовка имеют один на той же нумерованной строке! – M.M 11 April 2017 в 13:36

Это работает, с опцией «удалить неиспользованный». Я могу использовать одну глобальную функцию для проверки глобальных параметров.

//
#ifndef __sassert_h__
#define __sassert_h__

#define _cat(x, y) x##y

#define _sassert(exp, ln) \
extern void _cat(ASSERT_WARNING_, ln)(void); \
if(!(exp)) \
{ \
    _cat(ASSERT_WARNING_, ln)(); \
}

#define sassert(exp) _sassert(exp, __LINE__)

#endif //__sassert_h__

//-----------------------------------------
static bool tab_req_set_relay(char *p_packet)
{
    sassert(TXB_TX_PKT_SIZE < 3000000);
    sassert(TXB_TX_PKT_SIZE >= 3000000);
    ...
}

//-----------------------------------------
Building target: ntank_app.elf
Invoking: Cross ARM C Linker
arm-none-eabi-gcc ...
../Sources/host_if/tab_if.c:637: undefined reference to `ASSERT_WARNING_637'
collect2: error: ld returned 1 exit status
make: *** [ntank_app.elf] Error 1
//
0
ответ дан user4978854 21 August 2018 в 07:35
поделиться
  • 1
    Если он вообще работает, он будет делать это только в источнике исполняемого файла. – Coder 3 August 2015 в 22:30
Другие вопросы по тегам:

Похожие вопросы: