How to deal with strict enumerations in plain C? - c

Take a look at the following code:
typedef enum {
A, B, C
} Foo;
int foo(Foo x) {
switch(x) {
case A: return 1;
case B: return 2;
case C: return 3;
}
}
GCC 10.2 outputs
<source>:11:1: warning: control reaches end of non-void function [-Wreturn-type]
11 | }
| ^
This is because I can pass something like 42 to foo, not only A, B, or C. So the question is: how to tell GCC that only A, B, or C can be handled by the switch statement, otherwise the behavior is undefined? Compiler-specific functionality is acceptable.
Let me point some solutions that don't satisfy me. First, I could just insert default: __builtin_unreachable(); but this would penetrate case analysis: imagine that apparently I'm adding the D variant and the compiler would not tell me that D is unhandled.
Second, I could insert if (x > C) { __builtin_unreachable(); } before the switch statement, but this is too impossible because switch(x) is actually generated by a macro which doesn't know about the variants of Foo, it knows nothing but some variable x.
Third, I could insert #pragma GCC diagnostic ignored "-Wreturn-type", but again, switch(x) is generated by a macro and this is why I cannot revert the diagnostics to the previous state by #pragma GCC diagnostic pop.
Fourth, I could use an array instead of switch but the returned expressions are not constant and are provided by a user of the macro generating switch(x).
And the last one: I could write return 42; after the switch statement but again I want to disable the warning automatically inside the macro generating switch(x) because it's used extensively in my codebase.
Godbolt

If you feel like engaging in some light masochism, you could crudely implement exception-like behavior using setjmp and longjmp:
#include <stdlib.h>
#include <setjmp.h>
#include <stdio.h>
typedef enum Foo {
A, B, C
} Foo;
#define ENUM_OUT_OF_RANGE -1
jmp_buf env;
int foo( Foo x )
{
switch ( x )
{
case A: return 1;
case B: return 2;
case C: return 3;
default: longjmp( env, ENUM_OUT_OF_RANGE ); // "throw" ENUM_OUT_OF_RANGE
}
}
int main( void )
{
int ex;
if ( (ex = setjmp( env )) == 0 ) // "try" block
{
Foo arr[] = {A, B, C, 42};
for ( size_t i = 0; i < 4; i++ )
{
printf( "value of %d = %d\n", arr[i], foo( arr[i] ) );
}
}
else // "catch" block
{
if ( ex == ENUM_OUT_OF_RANGE )
{
fprintf( stderr, "foo was called with a value outside the range of Foo\n" );
}
}
return 0;
}
Builds with no warnings as follows (at least on my system):
gcc -o exceptions -std=c11 -pedantic -Wall -Werror exceptions.c
Output:
$ ./exceptions
value of 0 = 1
value of 1 = 2
value of 2 = 3
foo was called with a value outside the range of Foo

Related

How to change the value of a variable without the compiler knowing?

I want to verify the role of volatile by this method. But my inline assembly code doesn't seem to be able to modify the value of i without the compiler knowing. According to the articles I read, I only need to write assembly code like __asm { mov dword ptr [ebp-4], 20h }, I think I write the same as what he did.
actual output:
before = 10
after = 123
expected output:
before = 10
after = 10
Article link: https://www.runoob.com/w3cnote/c-volatile-keyword.html
#include <stdio.h>
int main() {
int a, b;
// volatile int i = 10;
int i = 10;
a = i;
printf("before = %d\n", a);
// Change the value of i in memory without letting the compiler know.
// I can't run the following statement here, so I wrote one myself
// mov dword ptr [ebp-4], 20h
asm("movl $123, -12(%rbp)");
b = i;
printf("after = %d\n", b);
}
I want to verify the role of volatile ...
You can't.
If a variable is not volatile, the compiler may optimize; it does not need to do this.
A compiler may always treat any variable as volatile.
How to change the value of a variable without the compiler knowing?
Create a second thread writing to the variable.
Example
The following example is for Linux (under Windows, you need a different function than pthread_create()):
#include <stdio.h>
#include <pthread.h>
int testVar;
volatile int waitVar;
void * otherThread(void * dummy)
{
while(waitVar != 2) { /* Wait */ }
testVar = 123;
waitVar = 3;
return NULL;
}
int main()
{
pthread_t pt;
waitVar = 1;
pthread_create(&pt, 0, otherThread, NULL);
testVar = 10;
waitVar = 2;
while(waitVar != 3) { /* Wait */ }
printf("%d\n", testVar - 10);
return 0;
}
If you compile with gcc -O0 -o x x.c -lpthread, the compiler does not optimize and works like all variables are volatile. printf() prints 113.
If you compile with -O3 instead of -O0, printf() prints 0.
If you replace int testVar by volatile int testVar, printf() always prints 113 (independent of -O0/-O3).
(Tested with the GCC 9.4.0 compiler.)

GCC: warning on unused return [duplicate]

This question already has answers here:
How to raise warning if return value is disregarded?
(8 answers)
Closed 7 years ago.
Problem statement
I use a return integer to propagate errors through my code. I would like gcc to provide me with a warning if I accidentally forget to propagate the error (i.e. when I forget to use the return integer).
Example
Consider this very simple example test.c:
// header
int test ( int a );
// function
int test ( int a )
{
if ( a<0 ) return 1;
return 0;
}
// main program
int main ( void )
{
int a = -10;
test(a);
return 0;
}
Expected behavior
$ gcc -Wunused-result main.c
Warning: main.c:19 ... unused return ...
or alternatively using Wall or Wextra or another option.
Needless to say, my compiler does not provide the warning with any of these options. One of my mistakes already took me frustratingly long to find...
// header
int test ( int a ) __attribute__ ((warn_unused_result));
// function
int test ( int a )
{
if ( a<0 ) return 1;
return 0;
}
// main program
int main ( void )
{
int a = -10;
test(a);
return 0;
}
It should work now.
In gcc and clang, you can mark specific functions with the warn_unused_result attribute and it will let you know if you ignore the result (assuming you're not using the -Wno-unused-result flag, of course).
Unfortunately, I'm not aware of a way to get those compilers to apply this to all functions globally, you have to do it explicitly on a case-by-case basis.
In any case, doing it globally would cause some rather annoying behaviour from things like printf where you may not care about the return code.

C structure dereference chain efficiency

This one is about dereferencing stucture variables in a chain. Please consider this code:
struct ChannelInfo
{
int iData1;
int iData2;
int iData3;
int iData4;
}
struct AppInfo
{
struct ChannelInfo gChanInfo[100];
} gAppInfo;
void main()
{
gAppInfo.gChannelInfo[50].iData1 = 1;
gAppInfo.gChannelInfo[50].iData2 = 2;
gAppInfo.gChannelInfo[50].iData3 = 3;
gAppInfo.gChannelInfo[50].iData4 = 4;
foo1();
foo2();
}
void foo1()
{
printf("Data1 = %d, Data2 = %d, Data3 = %d, Data4 = %d", gAppInfo.gChannelInfo[50].iData1, gAppInfo.gChannelInfo[50].iData2, gAppInfo.gChannelInfo[50].iData3, gAppInfo.gChannelInfo[50].iData4);
}
void foo2()
{
struct ChannelInfo* pCurrrentChan = &gAppInfo.gChanInfo[50];
printf("Data1 = %d, Data2 = %d, Data3 = %d, Data4 = %d", pCurrrentChan->iData1, pCurrrentChan->iData2, pCurrrentChan->iData3, pCurrrentChan->iData4);
}
Is foo2() any faster than foo1()? What happens if the array index was not a constant, being asked for by the user? I would be grateful if someone could profile this code.
this assembly version of your code could help you understand why your code is slower. But of course it could vary depending on the target architecture and you optimization flags ( Commpiling with O2 or O3 flags produce the same code for foo1 and foo2 )
In foo2 the address of ChannelInfo is stored in a register and address are calculated relative to the value stored in the register. Or in the worst case in the stack (local variable ) where in that case it could be as slow as foo1.
In foo1 the variable address for printf are calculated relative to the variable gAppInfo stored in memory heap (or in cache ).
As per #Ludin's request I added these numbers for reference :
Execution of an instruction : 1 ns
fetch from main memory : ~100 ns
assembly version with -O2 flags ( -Os and -O3 flags produce the same code )
Pondering things like this isn't meaningful and it is pre-mature optimization, because the code will get optimized so that both those functions are equivalent.
If you for some reason would not optimize the code, foo2() will be slightly slower because it yields a few more instructions.
Please not that the call to printf is approximately 100 times slower than the rest of the code in that function, so if you are truly concerned about performance you should rather focus on avoiding stdio.h instead of doing these kinds of mini-optimizations.
At the bottom of the answer I have included some benchmarking code for Windows. Because the printf call is so slow compared to the rest of the code, and we aren't really interested in benchmarking printf itself, I removed the printf calls and replaced them with volatile variables. Meaning that the compiler is required to perform the reads no matter level of optimization.
gcc test.c -otest.exe -std=c11 -pedantic-errors -Wall -Wextra -O0
Output:
foo1 5.669101us
foo2 7.178366us
gcc test.c -otest.exe -std=c11 -pedantic-errors -Wall -Wextra -O2
Output:
foo1 2.509606us
foo2 2.506889us
As we can see, the difference in execution time of the non-optimized code corresponds roughly to the number of assembler instructions produced (see the answer by #dvhh).
Unscientifically:
10 / (10 + 16) instructions = 0.384
5.67 / (5.67 + 7.18) microseconds = 0.441
Benchmarking code:
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
struct ChannelInfo
{
int iData1;
int iData2;
int iData3;
int iData4;
};
struct AppInfo
{
struct ChannelInfo gChannelInfo[100];
} gAppInfo;
void foo1 (void);
void foo2 (void);
static double get_time_diff_us (const LARGE_INTEGER* freq,
const LARGE_INTEGER* before,
const LARGE_INTEGER* after)
{
return ((after->QuadPart - before->QuadPart)*1000.0) / (double)freq->QuadPart;
}
int main (void)
{
/*** Initialize benchmarking functions ***/
LARGE_INTEGER freq;
if(QueryPerformanceFrequency(&freq)==FALSE)
{
printf("QueryPerformanceFrequency not supported");
return 0;
}
LARGE_INTEGER time_before;
LARGE_INTEGER time_after;
gAppInfo.gChannelInfo[50].iData1 = 1;
gAppInfo.gChannelInfo[50].iData2 = 2;
gAppInfo.gChannelInfo[50].iData3 = 3;
gAppInfo.gChannelInfo[50].iData4 = 4;
const size_t ITERATIONS = 1000000;
QueryPerformanceCounter(&time_before);
for(size_t i=0; i<ITERATIONS; i++)
{
foo1();
}
QueryPerformanceCounter(&time_after);
printf("foo1 %fus\n", get_time_diff_us(&freq, &time_before, &time_after));
QueryPerformanceCounter(&time_before);
for(size_t i=0; i<ITERATIONS; i++)
{
foo2();
}
QueryPerformanceCounter(&time_after);
printf("foo2 %fus\n", get_time_diff_us(&freq, &time_before, &time_after));
}
void foo1 (void)
{
volatile int d1, d2, d3, d4;
d1 = gAppInfo.gChannelInfo[50].iData1;
d2 = gAppInfo.gChannelInfo[50].iData2;
d3 = gAppInfo.gChannelInfo[50].iData3;
d4 = gAppInfo.gChannelInfo[50].iData4;
}
void foo2 (void)
{
struct ChannelInfo* pCurrrentChan = &gAppInfo.gChannelInfo[50];
volatile int d1, d2, d3, d4;
d1 = pCurrrentChan->iData1;
d2 = pCurrrentChan->iData2;
d3 = pCurrrentChan->iData3;
d4 = pCurrrentChan->iData4;
}
yes, foo2() is definitely faster than foo1() because foo2 refers a pointer to that memory block and everytime you access it just points there and fetches value from the mmory.

Switch statement code without a label [duplicate]

This question already has answers here:
Can I put code outside of cases in a switch?
(5 answers)
Closed 7 years ago.
How come ANSI C allows extraneous code before any case labels within a switch statement?
#include <stdio.h>
int main(void) {
const int foo = 1;
switch (foo) {
printf("wut\n"); /* no label, doesn't output */
case 1:
printf("1\n");
break;
default:
printf("other\n");
break;
}
return 0;
}
compiled with
$ gcc -pedantic -Wall -Werror -Wextra -ansi test.c
It compiles without warnings and executes fine - sans "wut".
It is allowed to put statements in switch without any label. Standard says about that:
C11: 6.8.4.2 The switch statement (p7):
In the artificial program fragment
switch (expr)
{
int i = 4;
f(i);
case 0:
i = 17;
/* falls through into default code */
default:
printf("%d\n", i);
}
the object whose identifier is i exists with automatic storage duration (within the block) but is never
initialized, and thus if the controlling expression has a nonzero value, the call to the printf function will
access an indeterminate value. Similarly, the call to the function f cannot be reached.

Calling C functions from fortran

I'm trying to call C functions using fortran (need this for a project).
So first was trying to simply call a non parametrized, void function via fortran.
Kindly help me resolve the following errors in the given code.
C Code for matrix multiplication:
#include <stdio.h>
extern "C"
{ void __stdcall mat();
}
void mat()
{
int m, n, p, q, c, d, k, sum = 0;
printf("Enter the number of rows and columns of first matrix\n");
scanf("%d%d", &m, &n);
int first[m][n];
printf("Enter the elements of first matrix\n");
for ( c = 0 ; c < m ; c++ )
for ( d = 0 ; d < n ; d++ )
scanf("%d", &first[c][d]);
printf("Enter the number of rows and columns of second matrix\n");
scanf("%d%d", &p, &q);
int second[p][q];
if ( n != p )
printf("Matrices with entered orders can't be multiplied with each other.\n");
else
{
printf("Enter the elements of second matrix\n");
for ( c = 0 ; c < p ; c++ )
for ( d = 0 ; d < q ; d++ )
scanf("%d", &second[c][d]);
int multiply[m][q];
for ( c = 0 ; c < m ; c++ )
{
for ( d = 0 ; d < q ; d++ )
{
for ( k = 0 ; k < p ; k++ )
{
sum = sum + first[c][k]*second[k][d];
}
multiply[c][d] = sum;
sum = 0;
}
}
printf("Product of entered matrices:-\n");
for ( c = 0 ; c < m ; c++ )
{
for ( d = 0 ; d < q ; d++ )
printf("%d\t", multiply[c][d]);
printf("\n");
}
}
}
int main()
{
mat();
return 0;
}
Also, the code for calling the function mat from fortran that I wrote is :
program mat_mult !This is a main program.
call mat()
stop
end
On executing the C file I get the following error:
matrix_mult.c:5: error: expected identifier or ‘(’ before string constant
On executing the fortran file using the F77 compiler, I get the following error:
/tmp/ccQAveKc.o: In function MAIN__':
matrix_mult.f:(.text+0x19): undefined reference tomat_'
collect2: ld returned 1 exit status
Kindly help me in identifying the error/correct code.
Thank you.
A few things first
1) I'm assuming you're using a C99 compiler because the C code you've written will not work on a C89 compiler.
2) extern "C" is for C++ programs: not C programs.
Not really sure which compiler you're using. Just assuming you're using gcc and gfortran since it looks like you're on a Linux based system.
gcc just adds a leading _ to the symbols: so mat becomes _mat.
gfortran adds both a leading and trailing _ to the symbols: so mat becomes _mat _.
To make C and Fortran talk
a) Remove the main function from the C code
b) Remove extern "C" declaration. This is a C++ declaration that tells the compiler that the routine mat should not have any name mangling.
c) Since you don't have any parameters, just assume _cdecl and change void mat() to void mat(). If you have to use stdcall, then you need to compile with --enable-stdcall-fixup. stdcall will be needed if the Fortran program has to pass parameters to the C program but that is a different ball game. Instead of _mat _, the compiler generates mat#0
d) Your C routine will now look like
#include <stdio.h>
void mat_()
{
...
}
/* No main */
e) Since the routine mat is not declared in the Fortran code, the compiler needs to know that it is external.
program mat_mult
external mat
call mat()
stop
end
f) Compile and link (say the C program is called mat.c and the fortran program is called matmul.f)
gcc -g -c mat.c
gfortran -g matmul.f mat.o -o matmul
There will probably be a whole load of comments recommending that you use F2003 or F2008 but if you have been told that you have to use F77, then you have to use F77.

Resources