What does the throw keyword mean in C - c

I tried googling it but all results were about C++'s throw std::exception().
I was reading through libraries (was curious how stuff like printf, malloc and FILE were implemented) and came across the definition for the malloc function:
extern void *malloc (size_t __size) __THROW __attribute_malloc__
__attribute_alloc_size__ ((1)) __wur;
When using the IDE (Visual Studio Code) to trace back to definitions for each thing, __THROW led to this:
# if !defined __cplusplus && __GNUC_PREREQ (3, 3)
// stuff that doesn't happen
# else
# if defined __cplusplus && __GNUC_PREREQ (2,8)
# define __THROW throw ()
# define __THROWNL throw ()
# define __NTH(fct) __LEAF_ATTR fct throw ()
# define __NTHNL(fct) fct throw ()
// continuation to the if-else macro
This confused me, as, as far as i know, c doesn't have exceptions and instead uses int error codes. Even more, why are there parentheses as in a function call?
What does it mean and what does it do in the presented case?

There is no throw keyword in C. That's a C++ thing.
As to why you find it in your code, the clue is right here in the preprocessor macros:
# if !defined __cplusplus && __GNUC_PREREQ (3, 3)
// stuff that doesn't happen
# else
# if defined __cplusplus && __GNUC_PREREQ (2,8)
# define __THROW throw ()
# define __THROWNL throw ()
# define __NTH(fct) __LEAF_ATTR fct throw ()
# define __NTHNL(fct) fct throw ()
// continuation to the if-else macro
This code is written so it will compile with either a C or C++ compiler. The C++ bit that references throw and other C++isms will only be compiled if a C++ compiler is used, as such a compiler will define the __cplusplus macro.
When you compile it with a C compiler, only the bit marked // stuff that doesn't happen will be used, not the else block.

The C 2017 standard doesn't define a throw keyword. The header file may be used by both C and C++ compilers and as #Barmar noted it doesn't apply to C (in C++, btw, throw() specifier means that the function doesn't throw exceptions).

There is no throw keyword in C. In C, the source text throw is an ordinary identifier.
The macro __THROW you show is replaced by nothing (an empty sequence of preprocessor tokens) when compiling in C, because the compilers the code you show is targeted for define __cplusplus only when compiling as C++, not when compiling as C. So, in C, !defined __cplusplus_ is true, and the // stuff that doesn't happen happens. You do not show that code, but it likely contains #define __THROW or equivalent, defining __THROW to be replaced by the empty sequence.
If you see other statements being used, where __THROW is defined to be replaced by throw (), then you are compiling in C++ mode, not C.

Related

conflicting declaration of C function With #ifdef __cplusplus

I failed to define overloading functions with error message of error: conflicting declaration of C function if enclosing by #ifdef __cplusplus blocks.
Below is a simple code for an easy view. This piece of code worked fine without #ifdef __cplusplus blocks.
However, my project code does need #ifdef __cplusplus as it involves combination of C and C++ codes.
Command lines after #ifdef __cplusplus block should be C++, why did it fail to define the overloading function? How to fix this problem with presence of #ifdef __cplusplus blocks?
#include <iostream>
using namespace std;
#ifdef __cplusplus
extern "C"
{
#endif
int add(int x)
{
return x;
}
int add(int x, int y)
{
return x + y;
}
int main() {
// cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!
int X = add(2);
int Z = add(8,2);
cout <<X<<" "<<Z<<endl;
return 0;
}
#ifdef __cplusplus
}
#endif
Command lines after #ifdef __cplusplus block should be C++
First of all, I believe you have a misconception of #ifdef __cplusplus, this macro only checks if your compiler is a C++ compiler or not.
You rather need focus on extern "C" {}. This block of code explicitly tells your compiler, that codes inside this block must be in C language(not C++).
This is important since C and C++ have different mechanisms of storing and calling functions from binary. (Called name mangling). Better to say, C and C++ binaries are not compatible. So extern "C" will tell your compiler that your functions C codes, and those function names are not mangled.
So #ifdef __cplusplus checks if your code is C or C++; if your code is in C++, insert extern "C" { that tells your compiler that those codes in this block are C code.
And since function overloading is not a part of C language, your compiler will cause an error inside that block. (This matters with name mangling).
But this macro is mostly used in header files, not source files. Because the purpose of this macro is to enable your code to be included in both C and C++ code, but source files cannot be and must not be included by another source.

Error C2660 : function does not take X arguments

I am converting some legacy C code to C++.
A header file contains a macro P
#ifndef P
# ifdef __STDC__
# ifndef __HIGHC__
# define USE_ANSI_PROTOTYPES
# endif
# endif
# ifdef __sgi__
# define USE_ANSI_PROTOTYPES
# endif
# ifdef USE_ANSI_PROTOTYPES
# define P(s) s
# else
# define P(s) ()
# endif
#endif
In my case the USE_ANSI_PROTOTYPES evaluates to not defined.
Another header file uses the macro P in a function declaration.
extern void long2str P((unsigned char *str,int pos,long clong));
The function is then called at certain places in code like
long2str(tmp_str, 0, seg_used(seg)); // <= error on this line
However VS2012 flags error on lines where the function is called
error C2660: 'long2str' : function does not take 3 arguments
What could be going wrong?
Unless you are using a C compiler from the 1980s, you should make sure that the first branch of the #ifdef is taken.
In this case, find out why the USE_ANSI_PROTOTYPES is not defined. And then either define it or remove the #ifdef section and define the P macro unconditionally.
The Microsoft compiler doesn't define the __STDC__ macro (for whatever reason), see https://msdn.microsoft.com/en-us/library/b0084kay.aspx.
Explanation:
Back in the 1980 (before ANSI C89 and ISO C90), functions were declared like this:
extern void long2str ();
That's it. No parameter names, no types, just the function name (and if you are lucky, the return type).
ISO C90 introduced function prototypes, and the preferred way of declaring functions became:
extern void long2str (unsigned char *str,int pos,long clong);
The P macro from your question can produce both variants when it is called with the parameters in double parentheses. The outer parentheses form a single macro argument, and the inner parentheses are only needed in the C90 case.

weird c function syntax

I know my C up to this point. I was looking at the source files of PHP I downloaded, and I saw this strange syntax:
PHPAPI int php_printf(const char *format, ...)
{
// code...
}
What does the PHPAPI do before the return type int? I've tried searching all over and I can't understand what this means. Is it a second return type? It can't be because the function does return an int. Maybe it extends to some other struct declared in a header file?
The hard way:
Go to the makefile and add in the line that compiles the sources: -E, by doing so you will see the source cose after the preprocessing phase.
The easy way:
Search all the project for PHPAPI:
find it in php.h:
#ifdef PHP_WIN32
#include "win95nt.h"
# ifdef PHP_EXPORTS
# define PHPAPI __declspec(dllexport)
# else
# define PHPAPI __declspec(dllimport)
# endif
#define PHP_DIR_SEPARATOR '\\'
#else
#define PHPAPI
#define THREAD_LS
#define PHP_DIR_SEPARATOR '/'
#endif
Now what you need to know is what is __declspec(dllexport) and what is __declspec(dllimport)
In the SO thread- What is __declspec and when do I need to use it?
see Alexander Gessler answer:
The canonical examples are __declspec(dllimport) and
__declspec(dllexport), which instruct the linker to import and
export (respectively) a symbol from or to a DLL.
// header
__declspec(dllimport) void foo();
// code - this calls foo() somewhere in a DLL
foo();
(__declspec(..) just wraps up Microsoft's specific stuff - to
achieve compatibility, one would usually wrap it away with macros)

Serial- / Socket IO and GCC nothrow attribute

I have functions which abstract serial- and socket IO (Linux / Windows) implemented in C.
All of them are marked as extern "C" because they may get called from C++ as well.
Is it safe to use __attribute__((__nothrow__)) (or MinGW Macro __MINGW_NOTHROW) here / can i assume no exceptions are thrown?
Called functions - Sockets:
(not all additions for WinSock listed)
socket
connect
send / recv
close (closesocket on Windows)
sendto / recvfrom
Called functions - Serial:
Since serial IO code differs to much between windows / linux not all are listed here
Linux (GNU)
open
tcgetattr
read / write
close
Windows (MinGW)
CreateFile
GetCommState / SetCommTimeouts
ReadFile / WriteFile
CloseHandle
Since ANSI C has no exceptions (please correct me if I'm wrong) they won't be thrown, but how about GCC extensions and OS API calls?
Documentation: http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html (see nothrow).
C
GNU C (Linux) uses __THROW macro instead of __MINGW_NOTHROW.
While the MinGW one is __nothrow__ attribute only, __THROW contains __leaf__ attribute too.
C++
If you use C++, __THROW has another meaning: throw() - indicating that no exception is thrown (analog to __nothrow__; but defined in the C++ standard).
So it depends on whether you compile with C or C++, not on what you call the functions from (GNU C / C++ only!).
Example:
void f() __THROW;
Treated as ...
GNU C:
void f() __attribute__((__nothrow__, __leaf__))
GNU C++:
void f() throw()
Functions1) which are cancellation points, therefore not marked with
__THROW:
open()
read()
write()
close()
connect()
send()
recv()
close()
sendto()
recvfrom()
Functions1) marked with __THROW:
tcgetattr()
socket()
At least, these are save to __nothrow__.
In contrast, MinGW doesn't differ C from C++; in both cases the attribute is set.
Using example from above, __nothrow__ is set on C and C++:
void f() __attribute((__nothrow__))
Functions1) not marked with __MINGW_NOTHROW:
socket()
connect()
send()
recv()
closesocket()
sendto()
recvfrom()
CreateFile()
GetCommState()
SetCommTimeouts()
ReadFile()
WriteFile()
CloseHandle()
To make it short: none!
Compatibility
With C
C language code that is expecting to interoperate with C++ should be
compiled with -fexceptions. This will make debugging a C language
function called as part of C++-induced stack unwinding possible.
In particular, unwinding into a frame with no exception handling data
will cause a runtime abort. If the unwinder runs out of unwind info
before it finds a handler, std::terminate() is called.
Please note that most development environments should take care of
getting these details right. For GNU systems, all appropriate parts of
the GNU C library are already compiled with -fexceptions.
( source: http://gcc.gnu.org/onlinedocs/libstdc++/manual/using_exceptions.html )
So compiling with -fexceptions and there's no need for equivalent attribute. If you only can mark specific functions you have to / should use __nothrow__.
But while using __nothrow__ attribute looks save only on GNU C++, and some functions of GNU C on Linux, it's not that clear on Windows.
Addendum:
To avoid some parts of this problem, i've written a macro similar to __THROW but usable on MinGW too:
#if defined __GNUC__
#ifndef __THROW
#ifdef __cplusplus
#define __THROW throw()
#else
#define __THROW __attribute__((__nothrow__))
#endif
#endif
#else
#define __THROW
#endif
Note: __leaf__ is not included.
1) Talking only about those which are listed on my question.
take care of gcc version, nothrow has been introduced with gcc 3.3!
you can port __THROW from sys/cdefs.h to mingw:
/* skip this entire part on linux (= glibc available)*/
#if defined __GNUC__ && !defined __linux__
/********* port __GNUC_PREREQ macro to mingw *********/
# if !defined __GNUC_PREREQ
# if !defined __MINGW_H
# include <_mingw.h>
# define __GNUC_PREREQ(major, minor) __MINGW_GNUC_PREREQ(major, minor)
# else
# if defined (__GNUC_MINOR__)
# define __GNUC_PREREQ(major, minor) __GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))
# else
# define __GNUC_PREREQ(major, minor) 0
# endif
# endif
#endif /* __GNUC_PREREQ */
/********* from gnu c blirary *********/
/* All functions, except those with callbacks or those that
synchronize memory, are leaf functions. */
# if __GNUC_PREREQ (4, 6) && !defined _LIBC
# define __LEAF , __leaf__
# define __LEAF_ATTR __attribute__ ((__leaf__))
# else
# define __LEAF
# define __LEAF_ATTR
# endif
/* GCC can always grok prototypes. For C++ programs we add throw()
to help it optimize the function calls. But this works only with
gcc 2.8.x and egcs. For gcc 3.2 and up we even mark C functions
as non-throwing using a function attribute since programs can use
the -fexceptions options for C code as well. */
# if !defined __cplusplus && __GNUC_PREREQ (3, 3)
# define __THROW __attribute__ ((__nothrow__ __LEAF))
# define __THROWNL __attribute__ ((__nothrow__))
# define __NTH(fct) __attribute__ ((__nothrow__ __LEAF)) fct
# else
# if defined __cplusplus && __GNUC_PREREQ (2,8)
# define __THROW throw ()
# define __THROWNL throw ()
# define __NTH(fct) __LEAF_ATTR fct throw ()
# else
# define __THROW
# define __THROWNL
# define __NTH(fct) fct
# endif
# endif
#else /* Not GCC. */
# define __inline /* No inline functions. */
# define __THROW
# define __THROWNL
# define __NTH(fct) fct
#endif /* GCC. */
see glibc - sys/cdefs.h for full code.
edit: __GNUC_PREREQ can be replaced with __MINGW_GNUC_PREREQ(major, minor), then you don't have to redifine it as above.

Error C2491 on C source with Visual studio 8

i'm really noob in C. I just need to compile a ANSI C source to get a dll.
During compilation i get this error:
C2491: 'SelectML': definition of dllimport function not allowed
Where SelectML is a public function with this definition:
int CALLINGCONV SelectML(WORD fid, int nSlot)
{
WORD SW;
int x;
BYTE pSend[2];
pSend[0]=(BYTE)((fid&0xff00)>>8);
pSend[1]=(BYTE)(fid&0x00ff);
x=SendAPDUML(hCards[nSlot],APDU_SELECT,2,0,pSend,0,&SW);
if (x!=C_OK) return x;
if (SW!=0x9000) return SW;
return C_OK;
}
I'm sure the C source is good, maybe it is just a Visual Studio configuration...
This is another linked header:
#ifndef LIBSIAECARDT_H
#define LIBSIAECARDT_H
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(USE_STDCALL)
#define USE_STDCALL 1
#endif
#ifdef _WIN32
# if USE_STDCALL == 1
# define CALLINGCONV_1 _stdcall
# else
# define CALLINGCONV_1
# endif
# if defined(LIBSIAE_EXPORTS)
# define LIBSIAEAPI __declspec(dllexport)
# else
# define LIBSIAEAPI __declspec(dllimport)
# endif
# define CALLINGCONV LIBSIAEAPI CALLINGCONV_1
#else // ! _WIN32
# define CALLINGCONV
# define LIBSIAEAPI
# define CALLINGCONV_1
typedef unsigned int UINT;
#endif // _WIN32
It's common to have a macro like CALLINGCONV conditionally defined as __declspec(dllimport) or __declspec(dllexport) so that the same header file can be used in the library source and in the code using the library. Your build should probably define something that makes it use dllexport. Check how CALLINGCONV is defined or (preferably) consult any build documentation that came with the code.
Quoted in MSDN says it all. Do not define the function. Declaration is good. What you are doing here is defining SelectML which for sure is generating your C2491 Error.
Here's an alternative. Stop using MSVC. They explicitly dropped support for anything after C90. Use an actual C compiler for C code.

Resources