Skip to content

Conversation

@spgarbet
Copy link

Original at r-lib/yaml#22

Per Tim Hesterberg:

In C, the assert macro takes a boolean value, or something that can convert to a boolean value. At run time, if this value is true, nothing happens and the program continues. On false, an assertion is raised, the program crashes, and the line with the assert is printed out. So an assertion written:

assert(size > 0);

Would get something like this when the assertion is triggered:

Assertion failed: 'size > 0'

Probably with more information like file name, line number, etc. However, there is no second argument to assert to specify why the assert exists. To do that, a string literal can be inserted into the boolean argument like so:

assert(size > 0 && "need at least one element");
Assertion failed: 'size > 0 && "need at least one element"'

The string literal has the type of a character array. Arrays can decay to a pointer to the element type. Pointers can convert to boolean value, with non-null pointers becoming a true value. Arrays that decay to pointers always decay to non-null pointers. This means that string literals in a boolean context evaluate to true. By boolean logic, (X && true) == (X), so it is safe to append '&& "message"' to any boolean expression without changing its value.

If there is a code path that should never be reached, an assertion that always fails should be inserted. The smallest such form is:

assert(0);

Then, if a message is required:

assert(0 && "oops");

Both the arguments evaluate to false and the assertion always triggers. However, a common mistake with asserts is to omit the '0 &&' and write:

assert("oops");

With this mistake, "oops" always evaluated to true, the assertion never triggers, and this code branch is no longer protected. I think it's a good idea to pass on to the package maintainer so that future versions will not have this problem.

@i-ky
Copy link

i-ky commented Feb 15, 2022

I don't think that adding string literals into assert() conditions is a good idea. Compilers know that string literals are not NULL, that X && true == X and that && true is unneeded and, therefore, suspicious. I guess that compilers may issue a warning in such case.

I don't know the exact reason, but cppreference.com recommends a different way of incorporating messages into assert(), namely:

assert(("There are five lights", 2 + 2 == 5));

In any case, if additional information is desired on assert() failures, I would recommend adding a custom macro, e.g.:

#define assert_with_reason(expression, reason) assert((reason, expression))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants