How to avoid getting "constant expression" on if's? - c

I have an assert macro that resolves to an if, something like this:
#define assert(expr) \
if (!(expr)) \
{ \
handle_failed_assert(); \
}
Ignore how handle_failed_assert() works, and you don't need to cite the do { ... } while(0) trick. Please, focus on the functionality behind this.
Now, the real question comes. Sometimes I want to force and assert, and make it meaningful. So we use this:
assert(!"Assert cause carefully described.");
The problem is that we have this compiler, vrxcc, based on RVCT 2.2, that throws this warning when compiling that:
#236-D: controlling expression is constant
Of course, that resolves to a compile constant if.
How could I trick the compiler into accepting that?

Your problem ultimately boils down to "my compiler is too smart, how do I make it stop complaining about something that, yes, is true and is often a programmer mistake, but in this case is not a programmer mistake". There are only two ways to do that:
Outwit the compiler. This is compiler-dependent.
Tell the compiler "don't complain, this is not a mistake." This is compiler-dependent.
I know nothing about vrxcc. R's comment goes towards doing the first. This sort of thing is almost guaranteed to work:
extern int __truefunc(void);
#define assert(expr) ((__truefunc() && (expr)) || __assert_fail(#expr))
where truefunc is a function that always returns 1, and that you can compile separately to outwit the compiler. The cost, of course, is that darned useless run-time call.
The "tell the compiler" method is nicer, but requires some sort of compiler documentation assist.
Addendum: it occurred to me in the shower that in your particular case, you've already decided to panic, so you could just have a panic function, and call that here. The disadvantage is that you have to change all your existing common_assert(!"some string") calls, but at least you can do that mechanically.
It might be nice if the language had a two-argument assert built in or as a standard thing. The FreeBSD kernel uses KASSERT for this these days, more or less as:
#define KASSERT(expr, panic_args) \
do { if (!(expr)) panic panic_args; } while (0)
which is a bit klunky syntactically, but is nicely flexible:
KASSERT(foo.field == FOO_MAGIC,
("memory overwrite of foo data structure: %d != %d",
foo.field, FOO_MAGIC));

Related

Is there a tool that checks what predefined macros a C file depends on?

To avoid impossible situation one could reduce the problem to two cases.
Case 1
The first (simplest) case is situation where the preprocessor has a chance to detect it, that is there's a preprocessor directive that depends on a macro being predefined (that is defined before the first line of input) or not. For example:
#ifdef FOO
#define BAR 42
#else
#define BAR 43
#endif
depends on FOO being predefined or not. However the file
#undef FOO
#ifdef FOO
#define BAR 42
#endif
does not. A harder case would be to detect if the dependency actually does matter, which it doesn't in the above cases (as neither FOO or BAR affects the output).
Case 2
The second (harder) case is where successful compilation depends on predefined macros:
INLINE int fubar(void) {
return 42;
}
which is perfectly fine as far as the preprocessor is concerned whether or not ENTRY_POINT is predefined, but unless INLINE is carefully defined that code won't compile. Similarily we could in this case it might be possible to exclude cases where the output isn't affected, but I can't find an example of that. The complication here is that in the example:
int fubar(void) {
return 42;
}
the fubar being predefined can alter the successful compilation of this, so one would probably need to restrict it to cases where a symbol need to be predefined in order to compile successfully.
I guess such a tool would be something similar to a preprocessor (and C parser in the second case). The question is if there is such a tool? Or is there a tool that only handles the first case? Or none at all?
In C everything can be (re)defined, so there is no way to know in advance what is intended to be (re)defined. Usually some naming conventions helps us to figure out what is meant to be a macro (like upper-case). Therefore it is not possible to have such tool. Of course if you assume that the compilation errors are caused by missing macro definitions then you can use them to analyze what is missing.

When did/does using #define to define a static function in C work?

Working in a new to me code base and I have come across some C code that looks like this:
static int* functionA(int* anInt);
#define functionA(anInt) ( <a 1 line '? :' function>)
Maybe this is obvious to people who’s C coding is a bit more fresh in their head than mine, but it looks a little odd to me. The compiler seems to agree as it spits out a message stating
error: ‘functionA’ declared ‘static’ but never defined.
(I am using gcc 4.8.2.)
As this is has turned up in some library code that we are evaluating I assume that for some compilers, some of the time, this is valid. Please could someone help explain when it is valid?
My best guess is this some old fashioned way of doing inline static function definitions. However there is every chance I am missing something subtle. An explanation of what is being achieved would also be helpful but really I want to know when this code is valid.
As this is has turned up in some library code that we are evaluating I
assume that for some compilers, some of the time, this is valid.
Please could someone help explain when it is valid?
If there is no actual definition of functionA in the source file where it is declared it is also not used, the compiler should issue "declared ‘static’ but never defined" as a warning.
However, if you are using the -Werror option the compiler would issue all warnings as errors... check if you are using that option.
https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
Your compiler is right, you declared a static function
static int* functionA(int* anInt);
but there is no definition for it, you then added a macro, that will replace every occurrence of functionA(value); in your code with (<a 1 line '? :' function>), hence you can't use the static function anymore even if it had a definition.
A function definition would be
static int *functionA(int* anInt)
{
/* do something with `aInt' */
}
while using the macro, the preprocessor will take this code
#define addnumbers(x, y) ((x) + (y))
double x = addnumbers(1.5, 6.7);
with
double x = ((1.5) + (6.7));
The #define does not define a function, it replaces apparent function calls in the code with an inlined expression. (The expression is ill-formed though unless I miss something; perhaps it is only a placeholder?) The only time the actual compiler sees functionA is in the static declaration; it complains that the function is never defined.
That compiler error comes unexpected to me -- I'd have assumed that the static declaration is ignored if the function is never called. (It is never called because the #define causes those "calls" to be replaced.) One should probably simply #define the static declaration away using an #if/#else construction if the "inlining by #define" is in effect.
By the way, with modern compilers and common optimization levels this should be unnecessary; the compiler would inline the function for you.

"with" macro in C

I was looking for a macro that will resemble the with-construct.
The usage should be something like:
with (lock(&x), unlock(&x)) {
...
}
It might be useful for some other purposes.
I came up with this macro:
#define __with(_onenter, _onexit, v) \
for (int __with_uniq##v=1; __with_uniq##v > 0; )\
for (_onenter; __with_uniq##v > 0; _onexit) \
while (__with_uniq##v-- > 0)
#define _with(x, y, z) __with(x, y, z)
#define with(_onenter, _onexit) _with(_onenter, _onexit, __COUNTER__)
It has 3 nested loops because it should:
Initialize loop counter (C99 only, of course)
Possibly initialize variable _onenter (such as with (int fd=open(..), close(fd)))
Allow break inside the code block. (continue is allowed too. And the macro could be adjusted to assert() it out)
I used it on the code for the XV6 OS and it seems quite useful.
My question is - what are the worst problems with such a macro? I mean, besides the mere usage of a C macro (especially one that implements new control-flow construct).
So far have found these drawbacks / problems:
No support for return or goto (but it can save some gotos in kernel code)
No support for errors (such as fd < 0). I think this one is fixable.
gnu89 / c99 and above only (loop counter. the unique variable trick is not necessary)
Somewhat less efficient than simple lock-unlock. I believe it to be insignificant.
Are there any other problems? Is there a better way to implement similar construct in C?
That macro scares me. I'd prefer the traditional approach using gotos.
That approach is primitive, but most C programmers are familiar with the pattern and if they're not, they can understand it by reading the local code. There is no hidden behavior. As a consequence, it's pretty reliable.
Your macro is clever, but it would be new to most everybody and it comes with hidden gotchas. New contributors would have to be thought rules such as "don't return or goto out of a with block" and "break will break out of the with block, not out of the surrounding loop". I fear mistakes would be common.
The balance would shift if you could add warnings for misuses of this construct to the compiler. With clang, that seems to be an option. In this case, misuses would be detected and your code would remain portable to other compilers.
If you're willing to restrict yourself to GCC and Clang, you can use the cleanup attribute. That would make your example look like this:
lock_t x = NULL __attribute__((cleanup(unlock)));
lock(&x);
And unlock will be called with a pointer to the variable when it goes out of scope. This is integrates with other language features like return and goto, and even with exceptions in mixed C/C++ projects.

Is there a gcc command line option to silence warning: passing argument n discards qualifiers from type

I'm trying to compile -Wall -Werror and its cramping my style.
I'm trying to make explicit that certain arguments are constants and then passing them to non const qualifying functions inside a large library.
P.S. I was mostly doing this to try to make it clear that certain variables are constants, is it good or bad c style to do this when dealing with a library functions that don't use const?
If you are passing those constants into routines as reference parameters or by pointer, then there may be a damn good reason for those warnings. How do you know that those routines won't modify your "constants"? What is that gonna screw up in the rest of your code, which you told that those variables won't ever change?
If you really know for sure that what you are doing is safe, and there is no good way to recode things to get rid of the warning, you can turn some warnings off in gcc using pragmas. Do this for as small an area of code as possible, and comment why you are doing it.
Do not abuse this privelege, or you are liable to arrested by the code police and sentenced to 9 months of community service coding in Ada. That'll cure you of ever complaining about C's warnings again.
Use the -Wno-ignored-qualifiers switch.
Sometimes, when compiling with -Wall -Wextra -Werror (as I do too because it is very good practice), you face recurring warnings that you may want to disable project wide, or on a per source file basis. One that I disable often in my projects for instance is -Wno-long-long. This is not bad practice, because you know what you are doing, and you don't want to control third party code.
As I understand though, you are trying to disable the warning for specific parts of the code, since otherwise it would ruin your effort putting const everywhere. In this case, do:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
OffendingThirdPartyFunction(MyConstParam);
#pragma GCC diagnostic pop
or also (untested, I don't know where to put the semicolons, and I don't have a working GCC here at work)
#define NO_WARNING(expr) \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wignored-qualifiers\"") \
expr \
_Pragma("GCC diagnostic pop")
NO_WARNING(OffendingThirdPartyFunction(MyConstParam));
Alternatively, you can use a cast. This is by far the most portable solution.
OffendingThirdPartyFunction((param_t*)MyConstParam);
Don't use a command-line option: the warning tells you that your code is not const-safe. It's right, your code isn't const-safe, although that's the fault of whoever wrote the library you're using.
If you disable the warnings then you won't get them any more even if you write code that's unsafe and it is your fault.
Instead, whenever one of the library functions takes a pointer-to-non-const, but guarantees not to modify the referand of the pointer, then cast the const-ness away from your pointer, and pass that. The cast serves as a record in the code that you (the programmer) are claiming that nothing invalid will happen, even though the type system can't prove that, and should probably be commented.
For example:
// in this library
void print_int(int *p) { printf("%d\n", *p); }
void set_int(int *p) { *p = 6; }
// your code
const int n = 5;
print_int((int*)(&n)); // warning suppressed for this call only,
// having carefully checked the print_int docs.
// further down your code
set_int(&n); // You *want* the compiler to stop this!
Or if you can be bothered (because you have a lot of such calls), write wrappers for the offending library functions:
void print_int_const(const int *p) { print_int((int*)(p)); }
// but no wrapper for set_int
Be aware that the cast also removes volatile (and in general accepts a lot of incorrect inputs). The overload prevents you accidentally using completely the wrong type, while the in-place cast doesn't.

C Error Checking Function

For my systems programming class we're doing a lot of programming in C and are required to error check most functions as we are currently learning to program with pthreads.
The reason I say this is not really homework, is that it is far above and beyond what is expected for this class. Simply checking each function individually is more than satisfactory. I just feel this is a time-consuming and messy method and hope for a neater solution.
I was wondering if anyone could show me how to write a function that takes any C function as a parameter, followed by all the required parameters for that function, along with a desired return value (in this case the correct one), and performs the following.
if(function_name(param1, param2, ...) != desired_return_value) {
fprintf(stderr, "program_name: function_name() failed\n");
perror("function_name(): ");
}
Is this possible? It's hardly required by our course, but it just irks me that virtually ever function I write has to have 4 lines of code to error check it. It makes it bloody hard to read.
Even some other suggestions would be good. I'm just trying to increase readability, so if this is totally the wrong direction, some correct direction would be much appreciated.
EDIT: This should compile under the gnu99 standard ideally :P
EDIT 2: In response to James McNellis:
The errors from our functions do not (I believe in this case), need to be handled. Notification only needs to be supplied. We have covered nothing on handling thread/process related errors (which is this subject in a nutshell).
Writing generic code in C without using macros isn't the easiest thing to do.
For a (very) basic solution using a variadic macro:
#define CALL_AND_CHECK(f, r, ...) \
do { \
if (f(__VA_ARGS__) != r) \
{ \
fprintf(stderr, "program_name: " #f "() failed\n"); \
perror(#f "(): "); \
} \
} while (0)
(See Why are there sometimes meaningless do/while and if/else statements in C and C++ macros? for why the "meaningless" do/while loop is used)
Note that printing out an error message and not actually handling the error is almost certainly a bad idea. Generally, different errors need to be handled in different ways, so generic code like this may not be particularly useful. If you don't want to try and recover from any of these errors, you could exit(), which might be okay for an assignment, though in a real-world program you wouldn't want to do that.

Resources