ImportC - D Programming Language
Description: D Programming Language
Keywords: D programming language

Menu

- Learn
- Documentation
  - Language Reference
  - Library Reference
  - Command-line Reference
  - Feature Overview
  - Articles
- Downloads
- Packages
- Community
  - Blog
  - Orgs using D
  - Twitter
  - Calendar
  - Forums
  - IRC
  - Community Discord
  - Wiki
  - GitHub
  - Issues
  - Get involved
  - Contributors
  - Foundation
  - Security Team
  - Donate
  - Sponsors
- Resources
  - Tour
  - Books
  - Tutorials
  - Tools
  - Editors
  - IDEs
  - run.dlang.io
  - Visual D
  - Acknowledgments
  - D Style
  - Glossary
  - Sitemap

Search
Report a bug
If you spot a problem with this page, click here to create a Bugzilla issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

# ImportC

Contents

1. ImportC Dialect
2. Invoking ImportC
   1. ImportC Files on the Command Line
   2. Importing C Files
3. Preprocessor
   1. Digital Mars C Preprocessor sppn.exe
   2. Gnu C Preprocessor
   3. Clang C Preprocessor
   4. dmpp C Preprocessor
4. Predefined Macros
5. Preprocessor Directives
   1. Line control
   2. Linemarker
   3. pragma
6. Implementation
   1. Enums
   2. Bit Fields
   3. Implicit Function Declarations
   4. #pragma STDC FENV_ACCESS
7. Limitations
   1. Exception Handling
   2. Const
   3. Volatile
   4. Restrict
   5. _Atomic
   6. Compatible Types
   7. Same only Different Types
   8. _Generic
8. Extensions
   1. Forward References
   2. Compile Time Function Execution
   3. Function Inlining
   4. Enum Base Types
   5. Register Storage Class
   6. Import Declarations
9. Gnu and Clang Extensions
   1. __attribute__((noreturn))
10. Visual C Extensions
11. Digital Mars C Extensions
12. ImportC from D's Point of View
    1. Module Name
    2. extern (C)
    3. Enums
    4. Tag Symbols
13. Wrapping C Code
14. Warnings
15. ImportC++
16. Other Solutions
    1. dpp by Atila Neves
    2. DStep by Jacob Carlborg
    3. htod by Walter Bright
17. How ImportC Works

Note: This document is under construction. Please excuse the dust and noise.

ImportC is a C compiler embedded into the D implementation. Its purpose is to enable direct importation of C files, without needing to manually prepare a D file corresponding to the declarations in the C file. It enables directly compiling C files into modules, and linking them in with D code to form an executable. It can be used as a C compiler to compile and link 100% C programs.

This is not a C reference manual nor programming tutorial. It describes the specifics of the dialect of C that ImportC is, and how to use it effectively.

ImportC and BetterC are very different. ImportC is an actual C compiler. BetterC is a subset of D that relies only on the existence of the C Standard library.

## ImportC Dialect

There are many versions of C. ImportC is designed to be an implementation of ISO/IEC 9899:2011, which will hereafter be referred to as C11. References to the C11 Standard will be C11 followed by the paragraph number. Prior versions, such as C99, C89, and K+R C, are not supported.

Adjustment to the ImportC dialect is made to match the behavior of the C compiler that the D compiler is matched to i.e. the associated C compiler. For example, on Win32 D is matched to the Digital Mars C compiler, and can be matched to the Visual C compiler using the -m32mscoff switch. Win64 D is matched to the Visual C compiler. On Posix targets, the matching C compiler is Gnu C or Clang C.

Further adjustment is made to take advantage of some of the D implementation's capabilities.

This is all covered in the rest of this document.

## Invoking ImportC

The ImportC compiler can be invoked in two ways:

- directly via the command line
- indirectly via importing a C file

### ImportC Files on the Command Line

### Importing C Files

## Preprocessor

ImportC does not have a preprocessor. It is designed to compile C files after they have been first run through the C preprocessor.

### Digital Mars C Preprocessor sppn.exe

sppn.exe runs on Win32 and is invoked as:

        sppn file.c

and the preprocessed output is written to file.i.

### Gnu C Preprocessor

The Gnu C Preprocessor can be invoked as:

        gcc -E file.c > file.i

### Clang C Preprocessor

The Clang Preprocessor can be invoked as:

        clang -E file.c > file.i

### dmpp C Preprocessor

The dmpp C Preprocessor can be invoked as:

        dmpp file.c

and the preprocessed output is written to file.i.

## Predefined Macros

ImportC does not predefine any macros.

Best Practices: To distinguish an ImportC compile vs some other C compiler, define __IMPORTC__ to be 1 when the preprocessor is run.

## Preprocessor Directives

Nevertheless, ImportC supports these preprocessor directives:

### Line control

C11 6.10.4

### Linemarker

linemarker directives are normally embedded in the output of C preprocessors.

### pragma

Pragma directives are ignored.

## Implementation

The implementation defined characteristics of ImportC are:

### Enums

enumeration-constants are always typed as int.

The expression that defines the value of an enumeration-constant must be an integral type and evaluate to an integer value that fits in an int.

    enum E { -10, 0x81231234 }; // ok
    enum F {  0x812312345678 }; // error, doesn't fit in int
    enum G { 1.0 };             // error, not integral type

The enumerated type is int.

### Bit Fields

There are many implementation defined aspects of C11 bit fields. ImportC's behavior adjusts to match the behavior of the associated C compiler on the target platform.

### Implicit Function Declarations

Implicit function declarations:

        int main()
        {
            func();  // implicit declaration of func()
        }

were allowed in K+R C and C89, but were invalidated in C99 and C11. Although many C compilers still support them, ImportC does not.

Rationale: Implicit function declarations are very error-prone and cause hard to find bugs.

### #pragma STDC FENV_ACCESS

This is described in C11 7.6.1

    #pragma STDC FENV_ACCESS on-off-switch

    on-off-switch:
        ON
        OFF
        DEFAULT

It is completely ignored.

## Limitations

### Exception Handling

ImportC is assumed to never throw exceptions. setjmp and longjmp are not supported.

### Const

C11 specifies that const only applies locally. const in ImportC applies transitively, meaning that although

    int *const p;

means in C11 that p is a const pointer to int, in ImportC it means p is a const pointer to a const int.

### Volatile

The volatile type-qualifier (C11 6.7.3) is ignored. Use of volatile to implement shared memory access is unlikely to work anyway, _Atomic is for that. To use volatile as a device register, call a function to do it that is compiled separately, or use inline assembler.

### Restrict

The restrict type-qualifier (C11 6.7.3) is ignored.

### _Atomic

The _Atomic type-qualifier (C11 6.7.3) is ignored. To do atomic operations, use an externally compiled function for that, or the inline assembler.

### Compatible Types

Compatible Types (C11 6.7.2) are identical types in ImportC.

### Same only Different Types

On some platforms, C long and unsigned long are the same size as int and unsigned int, respectively. On other platforms, C long and unsigned long are the same size as long long and unsigned long long. long double and long double _Complex can be same size as double and double _Complex. In ImportC, these types that are the same size and signed-ness are treated as the same types.

### _Generic

Generic selection expressions (C11 6.5.1.1) differ from ImportC. The types in Same only Different Types are indistinguishable in the type-name parts of generic-association. Instead of giving an error for duplicate types per C11 6.5.1.1-2, ImportC will select the first compatible type-name in the generic-assoc-list.

## Extensions

### Forward References

Any declarations in scope can be accessed, not just declarations that lexically precede a reference.

### Compile Time Function Execution

Evaluating constant expressions includes executing functions in the same manner as D's CTFE can.

### Function Inlining

Functions for which the function body is present can be inlined by ImportC as well as by the D code that calls them.

### Enum Base Types

Enums are extended with an optional EnumBaseType:

    EnumDeclaration:
        enum Identifier : EnumBaseType EnumBody

    EnumBaseType:
        Type

which, when supplied, causes the enum members to be implicitly cast to the EnumBaseType.

    enum S : byte { A };
    _Static_assert(sizeof(A) == 1, "A should be size 1");

### Register Storage Class

Objects with register storage class are treated as auto declarations.

Objects with register storage class may have their address taken. C11 6.3.2.1-2

Arrays can have register storage class, and may be enregistered by the compiler. C11 6.3.2.1-3

### Import Declarations

Modules can be imported with a CImportDeclaration:

    CImportDeclaration:
        __import ImportList ;

Imports enable ImportC code to directly access D declarations and functions without the necessity of creating a .h file representing those declarations. The tedium and brittleness of keeping the .h file up-to-date with the D declarations is eliminated. D functions are available to be inlined.

Imports also enable ImportC code to directly import other C files without needing to create a .h file for them, either. Imported C functions become available to be inlined.

The ImportList works the same as it does for D.

The ordering of CImportDeclarations has no significance.

An ImportC file can be imported, the name of the C file to be imported is derived from the module name.

All the global symbols in the ImportC file become available to the importing module.

If a name is referred to in the importing file is not found, the global symbols in each imported file are searched for the name. If it is found in exactly one module, that becomes the resolution of the name. If it is found in multiple modules, it is an error.

Note: Since ImportC has no scope resolution operator, only global symbols can be found, and a qualification cannot be added to specifiy which module a symbols is in.

Preprocessor symbols in the imported module are not available to the importing module, and preprocessing symbols in the importing file are not available to the imported module.

A D module can be imported, in the same manner as that of a ImportDeclaration.

Imports can be circular.

    __import core.stdc.stdarg; // get D declaration of va_list
    __import mycode;           // import mycode.c

    int foo()
    {
        va_list x;    // picks up va_list from core.stdc.stdarg
        return 1 + A; // returns 4
    }

mycode.c looks like:

    enum E { A = 3; }

Best Practices: Avoid using preprocessor #defines like #define A 3. Use the enum form shown in the above example. Prefer const declarations over #defines. Rewrite function-style preprocessor macros as inline functions.

## Gnu and Clang Extensions

gcc and clang are presumed to have the same behavior w.r.t. extensions, so gcc as used here refers to both.

### __attribute__((noreturn))

__attribute__((noreturn)) marks a function as never returning. gcc set this as an attribute of the function, it is not part of the function's type. In D, a function that never returns has the return type noreturn. The difference can be seen with the code:

        attribute((noreturn)) int foo();
        size_t x = sizeof(foo());

This code is accepted by gcc, but makes no sense for D. Hence, although it works in ImportC, it is not representable as D code, meaning one must use judgement in creating a .di file to interface with C noreturn functions.

Furthermore, the D compiler takes advantage of noreturn functions by issuing compile time errors for unreachable code. Such unreachable code, however, is valid C11, and the ImportC compiler will accept it.

Best Practices: C code that uses the noreturn attribute should at the very least set the return type to void.

## Visual C Extensions

## Digital Mars C Extensions

## ImportC from D's Point of View

There is no one-to-one mapping of C constructs to D constructs, although it is very close. What follows is a description of how the D side views the C declarations that are imported.

### Module Name

The module name assigned to the ImportC file is the filename stripped of its path and extension. This is just like the default module name assigned to a D module that does not have a module declaration.

### extern (C)

All C symbols are extern (C).

### Enums

The C enum:

    enum E { A, B = 2 };

appears to D code as:

    enum E : int { A, B = 2 }
    alias A = E.A;
    alias B = E.B;

The .min and .max properties are available:

    static assert(E.min == 0 && E.max == 2);

### Tag Symbols

Tag symbols are the identifiers that appear after the struct, union, and enum keywords, (C11 6.7.2.3). In C, they are placed in a different symbol table from other identifiers. This means two different symbols can use the same name:

        int S;
        struct S { int a, b; };
        S = 3;
        struct S *ps;

D does not make this distinction. Given a tag symbol that is the only declaration of an identifier, that's what the D compiler recognizes. Given a tag symbol and a non-tag symbol that share an identifier, the D compiler recognizes the non-tag symbol. This is normally not a problem due to the common C practice of applying typedef, as in:

        typedef struct S { int a, b; } S;

The D compiler recognizes the typedef applied to S, and the code compiles as expected. But when typedef is absent, as in:

        int S;
        struct S { int a, b; };

the most pragmatic workaround is to add a typedef to the C code:

        int S;
        struct S { int a, b; };
        typedef struct S S_t;    // add this typedef

Then the D compiler can access the struct tag symbol via S_t.

## Wrapping C Code

Many difficulties with adapting C code to ImportC can be done without editing the C code itself. Wrap the C code in another C file and then

    #include

it. Consider the following problematic C file file.c:

        void func(int *__restrict p);
        int S;
        struct S { int a, b; };

The problems are that

    __restrict

is not a type qualifier recognized by ImportC (or C11), and the struct S is hidden from D by the declaration

    int S;

. To wrap file.c with a fix, create the file file_ic.c with the contents:

        #define __restrict restrict
        #include "file.c"
        typedef struct S S_t;

Then, import file_ic; instead of import file;, and use S_t when

    struct S

is desired.

## Warnings

Many suspicious C constructs normally cause warnings to be emitted by default by typical compilers, such as:

    int *p = 3; // Warning: integer implicitly converted to pointer

ImportC does not emit warnings. The presumption is the user will be importing existing C code developed using another C compiler, and it is written as intended. If C11 says it is legal, ImportC accepts it.

## ImportC++

ImportC will not compile C++ code. For that, use dpp.

## Other Solutions

### dpp by Atila Neves

dpp code

dpp Article

From the Article:

> dpp is a compiler wrapper that will parse a D source file with the .dpp extension and expand in place any #include directives it encounters, translating all of the C or C++ symbols to D, and then pass the result to a D compiler (DMD by default).

Like DStep, dpp relies on libclang.

### DStep by Jacob Carlborg

DStep code

DStep Article

From the Article:

> DStep is a tool for automatically generating D bindings for C and Objective-C libraries. This is implemented by processing C or Objective-C header files and outputting D modules. DStep uses the Clang compiler as a library (libclang) to process the header files.

### htod by Walter Bright

htod converts a C .h file to a D source file, suitable for importing into D code. htod is built from the front end of the Digital Mars C and C++ compiler. It works just like a C or C++ compiler except that its output is source code for a D module rather than object code.

## How ImportC Works

ImportC's implementation is based on the idea that D's semantics are very similar to C's. ImportC gets its own parser, which converts the C syntax into the same AST (Abstract Syntax Tree) that D uses. The lexer for ImportC is the same as for D, but with some modifications here and there, such as the keywords and integer literals being different. Where the semantics of C differ from D, there are adjustments in the semantic analysis code in the D compiler.

This co-opting of the D semantic implementation allows ImportC to be able to do things like handle forward references, CTFE (Compile Time Function Execution), and inlining of C functions into D code. Being able to handle forward references means it is not necessary to even write a .h file to be able to import C declarations into D. Being able to perform CTFE is very handy for testing that ImportC is working without needing to generate an executable. But, in general, the strong temptation to add D features to ImportC has been resisted.

The optimizer and code generator are, of course, the same as D uses.

Better C
Live Functions
Copyright © 1999-2022 by the D Language Foundation | Page generated by Ddoc on Fri May 13 12:21:50 2022