On OpenSolaris ($^O eq 'solaris', vers. 2.11), I'm trying to build an XS module which uses the XPGv4v2/Single Unix Spec. understanding of struct msghdr, specifically for "ancillary data" interrogation.
However, the native perl (v5.8.4) was built without the requisite defines, and so the struct msghdr visible within my XS file is the older, BSD kind::
#include "EXTERN.h"
#include "perl.h" /* older, "msg_accrights"-style msghdr now visible */
#include "XSUB.h"
....
struct msghdr m;
m.msg_control = buf; /* ERROR, structure has no member named "msg_control" */
....
Supplying the "right" #defines (_XOPEN_SOURCE and _XOPEN_SOURCE_EXTENDED) breaks the build, since it changes a great many things that perl was expecting.
Is there an elegant way I can have the XS module use the structure definition I'd like?
You either have to use the definitions that your existing perl understands, or compile a new perl with the definitions that you want.
You don't need to replace the existing perl, though. You can install the new perl separately so they don't conflict.
If you want it both ways, you have to figure out which definitions your Perl has and write code that handles the right set of definitions. You might add a layer of abstraction so you can implement the underlying bits with either set of definitions. It's a lot of repeated code probably, but that's what portability is, unfortunately. :(
Related
I am writing linear list ADT as my practice in DS class. I use one header file, one function source code and a driver as a whole project. I defined macro "ELEMENT_TYPE" and "MAXSIZE" in the header file. My design is that I can #undef and immediately #define those two macros in the driver program to change "ELEMENT_TYPE" to any type the driver need.
If I put these code:
#undef ELEMENT_TYPE
#define ELEMENT_TYPE char
#undef MAXSIZE
#define MAXSIZE 50
into the header file after the #define, then in the driver program, the functions can be recognized properly(For example, insertion() 's second augment was "ELEMENT_TYPE", use those code above, IDE shows that insertion() receive a char augment in driver program.) However, if I put those codes into the driver below #include "foo.h", then IDE cannot recognize what augments the fuction should receive and use the initial definition of "ELEMENT_TYPE", in this case, int. Who know what was wrong in my program so that preprocessing directives don't work properly?
Here are the original codes:
driver.c
https://paste.ubuntu.com/p/6B76vmk6nN/
linear_list.c
https://paste.ubuntu.com/p/SHq4W5zkGM/
linear_list.h
https://paste.ubuntu.com/p/VY8vcgFD89/
PS:I am not native English speaker, so maybe there are some places I didn't express clearly. Point them out and I'll add more details if needed.
What it sounds like is happening is you're trying to #define these values in the driver in the hopes that they will stay defined in linear_list.c.
The problem is that these files are compiled separately and then linked. The #defines placed in driver.c cannot change those found in linear_list.c.
In order to have the effect I think you would like, you will need to change these values in linear_list.h. This is the best way to do this because that header is included in both the source files, and will presumably be #included in any file that works with the functions defined in linear_list.c. Please bear in mind that in order to see a change in the behavior of your program you will need to recompile not only driver.c but linear_list.c after changes to linear_list.h have been made.
As a side note, you should generally #include local headers like linear_list.h after you #include global headers like stdio.h and stdlib.h. In linear_list.c either of those headers could overwrite the values you've used in linear_list.h, if those identifiers are used. They look like they could be common enough, that it's not implausible that some header may use them, so it may be worthwhile to use a more unique identifier in the future. Which leads me to my final point: using #undef on these identifiers without checking if they're used somewhere else could lead to some problems, so you should generally check with #ifndef.
Hope that helps. If I've misunderstood please correct me.
EDIT: Clarification, additional information, credit to the other answer for reminding me of some important practices.
Macros in source code are replaced with the macro definition in effect at that point where the macro is used in the source code. So function declarations using ELEMENT_TYPE use the macro definition that most recently precedes the declaration. Changing the macro later will not change the function definition.
An alternative is to define ELEMENT_TYPE in the header only if it is not already defined:
#if ! defined ELEMENT_TYPE
#define ELEMENT_TYPE char
#endif
Then a source file can do either of:
Do not define ELEMENT_TYPE itself. When the header is included, the default type of char will be used.
Define ELEMENT_TYPE, then include the header. If desired, #undef ELEMENT_TYPE afterward. The type the source file provides in ELEMENT_TYPE will be used.
The driver and the program that uses it must use the same type. You cannot compile the driver using one type and the program using another. Compiling the program with a different type will not change the driver.
Below I have mentioned my small code and following are my queries regarding it -
1.I have opened /usr/src/linux-headers-3.13.0-32/include/linux/sched.h and I found the declaration of struct task_struct there , but when I try to declare an instance i.e variable of task_struct in the main function which includes the sched.h header , then also it is not able to identify the task_struct , Why ? , Why it is so
2. Even when I copied the complete code of that header file within my code i.e my .c file outside main class then the compiler shows error to include many other header files which was not a problem when I haven't copied the code of sched.h in my .c file
The Error being displayed by compiler in first case is - storage size of ‘temp’ isn’t known
My code is ( The code is just a representational view to tell my concept of Question)
#include<linux/sched.h>
int main(void)
{
struct task_struct temp;
printf("%d",temp.pid);
return 0;
}
Since the concepts are clear still something is lacking, Kindly share your suggestions.
My Linux system (Ubuntu 14.04) doesn't make struct task_struct available to user code:
$ rgrep 'task_struct' /usr/include
/usr/include/linux/hdreg.h:} task_struct_t;
/usr/include/linux/capability.h:struct task_struct;
The 2nd match (struct task_struct;) is just a forward-declaration of the type. Without the { ... } in the type declaration, it's just a forward-declaration, and in C (and C++) it's not possible to use a forward-declaration of a struct to create a variable of that type. That's why you are getting the storage size of ... isn't known error.
If you want to create a variable of type struct task_struct, you need to get its type declaration from another .h file, which has it with { ... }. You may have to install a package containing kernel headers for this. Please refer to your Linux distribution's documentation about finding and installing packages. Once the package is installed, you can use gcc -I /usr/.../... to specify directory names for gcc to look for .h files.
Most programs (including all userland programs, excluding the kernel itself and excluding kernel modules) don't need to create a variable of type struct task_struct though. If you explain in your question what you want to use struct task_struct for, you'll probably get a recommendation to accomplish your goal without using struct task_struct.
If you just want to print the PID of the current process, here is how to do it without struct task_struct:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
printf("%lld\n", (long long)getpid());
return 0;
}
Linux kernel headers are not designed to be included directly by user space programs. Even when you do this, this doesn't mean all content of such header is accessible to your code because of __KERNEL__ definitions which prevent this to happen. Linux kernel still tries to make it possible though for user code to use kernel headers so sometimes it is possible to do this, but you should stick to use kernel headers in kernel code and use C library otherwise.
This article may help.
Use it like this, sched.h is part of GNU
You can use like this:
#define _GNU_SOURCE
#ifndef __USE_GNU
#define __USE_GNU
#endif
#include <sched.h>
Now you can use all functions of sched.h
"struct task_struct" is undoubtedly present inside "linux/sched.h" . I suspect that you are building the module , in the wrong way , even your representational code looks like you are approaching the problem in user-space c programming style.
you should understand that Linux code is different from user space c programs in various aspects most basic being that it doesn't have a conventional "main" function as an entry point , but registration based mechanisms.You can read about building kernel modules from https://tldp.org/LDP/lkmpg/2.6/html/x181.html
I have a several structs in C and I want to write the following three functions:
get_field_list(...)
get_value_by_name(...)
set_value_by_name(...)
The first should return the list of fields defined in the struct. The second and third should get and set to the appropriate field by it's name.
I'm writing the structs. I'm willing to use any macro magic if required. It's OK if ill have a triplet of functions per each struct, but generic structures are better. Function pointers are also fine...
Basically I want some elementary reflections for structs....
Relevent:
https://natecraun.net/articles/struct-iteration-through-abuse-of-the-c-preprocessor.html
motivation
I'm trying to build a DAL (Data Access Layer) for a native app written in C. I'm using SQLite as a DB. I need to store various structures, and to be able to insert\ update\ get(select by key)\ search (select by query), and also to create\ drop the required table.
Basicly I want something like Hibernate for C ...
My best idea so far is to use MACROs, or some code generation utility, or a script, to create my structs together with meta-data I could use to dynamically build all my SQL commands. And also to have a small 'generic' module to implement all the basic procedures i need...
Different or better ideas to solve my actual problem will also be appreciated!
It can be done with "macro magic" as you suggested:
For each struct, create a header file (mystruct-fields.h) like this:
FIELD(int, field1)
FIELD(int*, field2)
FIELD(char*, string1)
Then, in another header (mystruct.h) you include that as many times as you need:
#define FIELD(T,N) T N;
struct mystruct {
#include "mystruct-fields.h"
};
#undef FIELD
#define FIELD(T,N) { STRINGIFY(T), STRINGIFY(N), offsetof(mystruct, N) },
#define STRINGIFY1(S) #S
#define STRINGIFY(S) STRINGIFY1(S)
struct mystruct_table {
struct {
const char *type, *name;
size_t offset;
} field[];
} table = {
#include "mystruct-fields.h"
{NULL, NULL, 0}
};
#undef FIELD
You can then implement your reflection functions, using the table, however you choose.
It might be possible, using another layer of header file includes, to reuse the above code for any struct without rewriting it, so your top-level code might only have to say something like:
#define STRUCT_NAME mystruct
#include "reflectable-struct.h"
#undef STRUCT_NAME
Honestly though, it's easier for the people who come after you if you just write the struct normally, and then write out the table by hand; it's much easier to read, your IDE will be able to auto-complete your types, and prominent warnings in the comments should help prevent people breaking it in future (and anyway, you do have tests for this right?)
The way to do it is to have your struct in a database format or xml or a text file or whatever format you are comfortable with. And use a C program to write a .h file for each struct. The .h file contains the struct , an enum of the fields, and array of char containing the names of each field. From there you can build anything you need. Preferably using a program generator.
Take a look at Metaresc library. It provides reflection capabilities in plain C. Metadata of types definition could be derived either from custom macro language that replaces standard C type definition semantics or from compiler debug info. Sample app is provided in README.md
I'm struggling with a design issue, and I'm trying to find the "Best Practice" answer for my situation.
Say I have a file called Logger.c (And Logger.h) that is responsible for logging actions in my program.
I want logger to be referenced by all my modules, so each module's has a
#include Logger.h.
Say I have a module called NTFS.c that is responsible for interaction with the NTFS FS, This module has special structs that are defined in its header, for example: NTFS_Partition.
Here is the problem:
On one hand, I want logger to be able to print to a log file a formatted representation of NTFS_Partition, and by that I must #include NTFS.h in Logger.h.
(Inside Logger.h)
#include NTFS_Partition
VOID Log_Partition(NTFS_Partition *part);
On the other hand, I am not sure Logger should re-reference modules that reference him.
Currently I'm seeing a two main choices:
1.Logger.h includes NTFS.h, and NTFS.c include Logger.h (This works)
2.I create a new header file called NTFS_Types.h that would be shared accross all the
modules, and would only contain the deceleration of NTFS structs (like NTFS_Partition).
Thanks a lot,
Michael.
You can create a shared header where all your structs are defined.
// structs.h
struct NTFS_Partition { .. };
struct FAT32_Partition { .. };
struct FAT16_Partition { .. };
Include it in logger.h.
// logger.h
#include "structs.h"
VOID Log_Partition(NTFS_Partition *part);
VOID Log_Partition(FAT32_Partition *part);
VOID Log_Partition(FAT16_Partition *part);
And include the logger.h in various source files.
// NTFS.c
#include "logger.h"
// FAT32.c
#include "logger.h"
// FAT16.c
#include "logger.h"
In C++, it's better to keep different irrelevant class definitions in different header files. But in C, placing different struct definitions in separate headers is probably an overkill.
It isn't entirely clear whether you are coding in C or C++; I'm going to assume C (so no overloaded function names, etc). It seems to me that you need to 'forward declare' your structures. In Logger.h, you write:
#ifndef LOGGER_H_INCLUDED
#define LOGGER_H_INCLUDED
struct NTFS_Partition; // No details - just the name (3 times)
struct FAT16_Partition;
struct FAT32_Partition;
...
void Log_NTFS_Partition(struct NTFS_Partition *part);
void Log_FAT16_Partition(struct FAT16_Partition *part);
void Log_FAT32_Partition(struct FAT32_Partition *part);
#endif // LOGGER_H_INCLUDED
This is all the information that a general client (of Logger.h) needs to know.
If a specific client is dealing with NTFS partitions, then it will not only include Logger.h but also NTFS.h, which will provide the full definition of struct NTFS_Partition { ... };, so the client can create instances of the structure and populate it with data. The code that implements the logging, Logger.c, will also include Logger.h and NTFS.h (and FAT16.h and FAT32.h), of course, so that it too can reference the members of the structures.
The header for a service (such as Logger.h) should provide the minimal amount of information that the clients of the service need for compilation. The implementation file may need more information, but can collect the extra information from headers that provide it.
One advantage of using the struct tag notation is precisely that it can be repeated as often as necessary without messing anything up. If you don't have C11, you can't repeat a typedef, so if you write:
typedef struct NTFS_Partition NTFS_Partition;
you must only include that line once. The difficulty is making sure that it is only defined once. For that, you probably use a header such as FSTypes.h to define the file-system typedefs that is properly protected by header guards and is included in any file that needs any of the typedefs. You can then reference the types without the preceding struct keyword.
If you code in C++, the typedef isn't necessary; struct NTFS_Partition; declares that there is such a structure type and also declares NTFS_Partition as a name for that type. If your code is bilingual, use the typedef version; it works in both C and C++.
Note that if your functions such as Log_NTFS_Partition() take an actual structure instead of a pointer to a structure, then you have to have the definition of the structure in scope. If the functions only take pointers, though, a forward declaration is sufficient.
What are some of the best ways to manage redundant typedefs used for platform independence from multiple middleware (operating systems, protocol stacks) vendors in the C programming language.
e.g.:
target.h
/* inclusion lock etc */
typedef char CHAR;
typedef unsigned char BYTE;
typedef unsigned short int WORD;
/* ... more of the same ... */
OS_types.h
/* inclusion lock etc */
typedef char CHAR;
typedef unsigned char BYTE;
typedef unsigned short int WORD;
/* ... more of the same ... */
At some point the compiler recognizes that it has two redundant typedef symbols and bails out with an error because this is simply not allowed by definition in C.
One possible way to do this without modifying the vendor's header would be to use the preprocessor with some header wrappers, e.g.
mytypes.h
#define BYTE VENDOR1_BYTE
#include <vendor1/types.h>
#undef BYTE
#define BYTE VENDOR2_BYTE
#include <vendor2/types.h>
#undef BYTE
typedef unsigned char BYTE;
This would result in the vendor's code generating different typedefs but hopefully mapped to the same actual type (unsigned char in the example). If the vendors are using different underlying types for the same type names then the method will likely not work.
That's a toughie. If I had to do something, I'd probably hold my nose and modify the third-party header-files -- possibly using macros to obtain conditional compilation of the offending typedefs.
Good luck.
If the vendor is responsive to feedback, you could beg them to move those generic type definitions into a separate file, e.g. types.h. If they're isolated in a separate file, it's much easier to manage. The solution could be as simple as removing their types.h and adding your own project-specific types.h which can do whatever it needs to do in your project.
Even better, beg them to use the standard C typedefs in stdint.h, i.e. uint16_t.
Otherwise, I'd suggest a modification to the vendor header files, done as cleanly as possible so it's easy to re-do when they next release code. Of course this all goes in your VCS so you can track exactly what changes you made!
One approach, although it could be a lot of work, is to build your own "wrapper" layers which provide only the functionality you need from each of the middleware vendors. If you keep each wrapper in its own compilation unit (.c file) that's the only place you'll need to refer to the vendor's header file. That gives you a way to prevent the conflicting types from "leaking" into your application, as you can use your own typedefs and translate them to the vendor-specific types in the wrapper.
As Steve suggested, modifying the header files might be the best solution, depending on how often the vendor ships new versions of their stuff. The overhead could get pretty high.
If you have the option to use C++ compilation for your own code (even if it is essentially C code) you could create namespace wrappers thus:
vendorA_target.h
namespace vendorA
{
extern "C"
{
#include <target.h>
}
}
vendorB_OS_types.h
namespace vendorB
{
extern "C"
{
#include <target.h>
}
}
Then in your own code. include these headers in place of the originals, and use scope-resolution, or if you are certain that types with the same name have identical or compatible definitions, simply us a using directive:
using vendorB::WORD
WORD timeout = 100 ;
vendorA::WORD x = 0xffff ;
Note that the extern "C" wrappers are not necessary if the headers already have them internally in __cplusplus macro conditionals - but it won't hurt.
Using C++ to compile C code imposes no overhead, but it does have stricter type comformaty checking, which while good for your code quality, may cause other headaches; especially if the third-party headers contain code that is invalid as C++. If the headers already have extern "C" declarations in __cplusplus macro conditionals, then they are already intended to be "C++-ready" and you may not have any such problems.
Unfortunately this method will not solve the problem of preprocessor macros with the same name. If you have that problem, you may have to #undef the macros from one header before including the other, or modify the headers.