I am new to C and have a maybe n00b question ...
Until now I thought a function is always defined as:
return_type function_name(function_arg_1 type, function_arg_1_name, ...)
But now I have found a C header file where a function is looking like this:
TIDY_EXPORT int TIDY_CALL tidyDetectedHtmlVersion( TidyDoc tdoc );
Which is more a:
i_do_not_know return_type i_do_not_know function_name(function_arg_1 type, function_arg_1_name)
The whole source can be seen at http://tidy.sourceforge.net/docs/api/tidy_8h-source.html
So what is "TIDY_EXPORT" and "TIDY_CALL" doing?
TIDY_EXPORT int TIDY_CALL are just modifiers to your function.
The function name is tidyDetectedHtmlVersion, it takes one parameter (tdoc) of type TidyDoc and returns an int.
TIDY_EXPORT is a macro defined in the platform.h file which defined as
00492 #if defined(_WIN32)
00493
00494 #if (defined(_USRDLL) || defined(_WINDLL)) && !defined(TIDY_EXPORT)
00495 #define TIDY_EXPORT __declspec( dllexport )
00496 #endif
which allows you to export the function when compiling the file as a library (e.g. dll)
As for TIDY_CALL, it's defined in the same file as:
00498 #ifndef TIDY_CALL
00499 #ifdef _WIN64
00500 # define TIDY_CALL __fastcall
00501 #else
00502 # define TIDY_CALL __stdcall
00503 #endif
00504 #endif
See this question for an explanation What is __stdcall?
TIDY_EXPORT and TIDY_CALL are macros. They are defined in platform.h.
In platform.h you have
#if (defined(_USRDLL) || defined(_WINDLL)) && !defined(TIDY_EXPORT)
#define TIDY_EXPORT __declspec( dllexport )
#endif
#ifndef TIDY_CALL
#ifdef _WIN64
#define TIDY_CALL __fastcall
#else
# define TIDY_CALL __stdcall
#endif
#endif
C is straightforward ... until macros get involved! Anything in ALL CAPS is probably a macro, which is a symbol which gets replaced with other text before compilation. That text can be defined to be anything, including an empty string. Luckily Doxygen has been used, so you can view the documentation http://tidy.sourceforge.net/docs/api/tidy_8h.html.
The file that is included:
#include "platform.h"
which you can read here, defines the macro.
For more info on macros in all their glory, read this.
TIDY_EXPORT is #defined as __declspec(dllexport) on Windows, to allow the function to be exported when Tidy is compiled as a DLL.
TIDY_CALL is a macro that expands to a platform-specific calling convention.
Both of these features are nonstandard extensions to the C language (which is why they are abstracted behind conditionally-compiled macros).
They are some macro defined somewere in your library. Do a text search in all the files and you probably finfd what they exactly defines. By using some paranormal diagnosys strategy I guess that TIDY export is some decoration to export the function from the library ( ie declspec(dllexport) in MS compilers, and TIDY_CALL specify the calling convention ( ie stdcall, pascal, and so on )
TIDY_CALL and so on are (It's my guess, but it's very probably) macros.
http://www.google.pl/search?sourceid=chrome&ie=UTF-8&q=macros+C%2B%2B#sclient=psy&hl=pl&source=hp&q=macros+C&aq=f&aqi=&aql=&oq=&pbx=1&fp=58c095358c87453c
They are macros, you can find them in the source code somewhere. TIDY_CALL for example is in platform.h
#ifndef TIDY_CALL
#ifdef _WIN64
# define TIDY_CALL __fastcall
#else
# define TIDY_CALL __stdcall
#endif
#endif
Related
I want to implement cross-platform build of my DLL with mingw32/VC.
At the moment everything is perfect with mingw side. However I have to wrap several things in macro for VC (it is built as /TC), for example:
void __attribute__((fastcall)) do1 ( A*, B , C, D );
bool __attribute__((fastcall)) ( *do2 ) ( E*, F );
The first one is simple, just a macro:
#ifdef __MINGW32__
#define __FASTCALL__ __attribute__((fastcall))
#elif _MSC_VER
#define __FASTCALL__ __fastcall
#else
#error "unsupported compiler"
#endif
The problem comes with the second one. Calling convention with a function pointer should looks like
bool ( __fastcall *do2 ) ( E*, F );
I tried the following macro (I skipped ifdef part):
#define __FASTCALLP__(func) (__attribute__((fastcall))(*##func))
#define __FASTCALLP__(func) (__fastcall *##func)
or if pass function name with asterisk:
#define __FASTCALLP__(func) (__attribute__((fastcall))(##func))
#define __FASTCALLP__(func) (__fastcall ##func)
Both failed with
error: pasting "*" and "function_name" does not give a valid
preprocessing token
May I wrong at my approach at all? Or I have to ifdef the whole code blocks or separate it to different files?
The problem is with the Concatenation-Operator ##. It will produce a new preprocessor token by concatenating the left- and right-hand-side, which does not exists (*do2 is no defined token)
Simply omit it and write like this (omitting #ifdefs):
#define __FASTCALL__(func) (__attribute__((fastcall))(func))
#define __FASTCALL__(func) (__fastcall func)
and use like this:
bool __FASTCALL__(do1)(A*, B , C, D);
bool __FASTCALL__(*do2)(E*, F);
There are preprocessor macros which define the name of a function inside it, __func__ for g++ and __FUNCTION__ for cl. (func is the c++ standard way of doing this (from dcl.fct.def.general) but it is not implmented everywhere)
For source which will be compiled by both of these compilers what should I do?
I have tried
#ifdef __func__
#define FUNCTION_NAME __func__
#else
#ifdef __FUNCTION__
#define FUNCTION_NAME __FUNCTION__
#else
#error "Function name macro not found"
#endif
#endif
but as it is not in a function the macros are not defined.
I have also tried
void implementation_detail() {
#ifdef __func__
#define FUNCTION_NAME __func__
#else
#ifdef __FUNCTION__
#define FUNCTION_NAME __FUNCTION__
#else
#error "Function name macro not found"
#endif
#endif
}
but that also gives an error.
How can I do this so it will work in multiple compliers?
I have found that there is a boost macro for this, BOOST_CURRENT_FUNCTION.
From looking at the source code here how this is implemented is they use an inline function like so.
inline void current_function_helper()
{
#if defined(__GNUC__) || (defined(__MWERKS__) && (__MWERKS__ >= 0x3000)) || (defined(__ICC) && (__ICC >= 600)) || defined(__ghs__) || defined(__DMC__)`
...
(also it is declared in a namespace called detail which is very wise)
I will use this.
EDIT: implementing __func__ will be in the Visual Studio customer technology preview out now, see here.
The following is taken from pngconf.h of libpng:
libpng version 1.6.3 - July 18, 2013
Copyright (c) 1998-2013 Glenn Randers-Pehrson
My question is, give the following macro preprocessors:
#ifndef PNG_FUNCTION
#define PNG_FUNCTION(type, name, args, attributes) attributes type name args
#endif
#ifndef PNG_EXPORTA
#define PNG_EXPORTA(ordinal, type, name, args, attributes)\
PNG_FUNCTION(PNG_EXPORT_TYPE(type),(PNGAPI name),PNGARG(args), \
extern attributes)
#endif
#ifndef PNG_EXPORT_TYPE
#define PNG_EXPORT_TYPE(type) PNG_IMPEXP type
#endif
#ifndef PNGAPI
#define PNGAPI PNGCAPI
#endif
#define PNGCAPI __cdecl
#ifndef PNGARG
#define PNGARG(arglist) arglist
#endif
are the following equivalent?
#ifndef PNG_EXPORTA
#define PNG_EXPORTA(ordinal, type, name, args, attributes)\
PNG_FUNCTION(PNG_EXPORT_TYPE(type),(PNGAPI name),PNGARG(args), \
extern attributes)
#endif
is equivalent to:
#ifndef PNG_EXPORTA
#define PNG_EXPORTA(ordinal, type, name, args, attributes)\
extern attributes PNG_EXPORT_TYPE(type) (PNGCAPI name) PNGARG(args)
#endif
which is finally equivalent to:
#ifndef PNG_EXPORTA
#define PNG_EXPORTA(ordinal, type, name, args, attributes)\
extern attributes PNG_IMPEXP type __cdecl name arglist
#endif
#OliverCharlesworth wrote:
Most compilers allow you to see the preprocessor output. For example, run GCC with the -E flag.
#lurker wrote:
On first glance, I would say the answer to the question of equivalence is "no". I think you inserted some commas where they didn't exist when you translated the PNG_FUNCTION macro. And welcome to the SO code parsing service. ;)
#JonathanLeffler wrote:
you have extern attributes, where you should have just extern attributes.
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)
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.