@funkylab it’s really to do with it not being standardised more than anything else. Like what is the expectation of preprocessing the following file lol.h

#ifndef foo
#define foo
#else
#pragma once
#endif
#include "lol.h"
Yo

Is it a single “Yo” or two lines of “Yo”?

If it was defined that it needed to be the first thing in a file following whitespace, I think i’f be fine with it.

@shugo gcc -EするとNULLが/usr/lib/gcc/x86_64-linux-gnu/13/include/stddef.hでdefineされていることがわかって、下記のように、Cなら(void *)に、C++なら整数になるみたいです。

:
#if defined (_STDDEF_H) || defined (__need_NULL)
#undef NULL /* in case <stdio.h> has defined it. */
#ifdef __GNUG__
#define NULL __null
#else /* G++ */
#ifndef __cplusplus
#define NULL ((void *)0)
#else /* C++ */
#define NULL 0
#endif /* C++ */
#endif /* G++ */
#endif /* NULL not defined and <stddef.h> or need NULL. */
#undef __need_NULL
:

@craigjb Who doesn't enjoy 101 #if... #ifndef...? 😆

Good luck and let us know how it goes.

@tknarr it's c

c23 has a way to mimick visibility, by building with `-Dmylib_private` and having:

```c
#ifndef mylib_private
#define mylib_private [[deprecated("private member")]]
#endif
```

but tbh even without that it's also possible to just say "do not touch any undocumented field, you've been warned" -- it's not like c doesn't already have api constraints that live in documentation (e.g. "this pointer may/may-not be NULL"), the less of those we have the better but one step at a time with improving semantics
@swags

most of c++'s compile time include costs is template instantiation, and those can't really be "opaque" anyway, and a better solution to it is to modularize your api, and to https://include-what-you-use.org/

headers should only include other headers if they *need* the definitions that are in those headers. if your types or functions don't, then you include the other header in the translation unit that does -- yes, a lot of people include random things in the header because they use it in the c file, but that doesn't make it a good practice

and yes, you can also do some sort of polymorphism by making types opaque and changing the definition based on a backend, but that's an exception rather than a rule

"hiding things from the user" is not worth the mess and runtime costs you get from it, now every structure needs to be heap allocated, now every public field needs to have a getter and setter, your library is twice as painful to use, unnecessarily slower, for a small benefit on the general case

if i intend data to be poked at, i document it, otherwise don't touch it. in c23 you can even go a step further:

```c
#ifndef mylib_private
# define mylib_private [[deprecated("private field")]]
#endif
```

now you compile your code with `-Dmylib_private`, but clients of the library would need to actively bypass compiler warnings to do stupid shit, and if you really really want, pre c23, you can even do things like wrapping private data in a `.private` struct field

making the whole struct opaque doesn't just impact "users can't touch it", it impacts your whole api, adds runtime constraints and limitations, and complicates memory management in many cases
include-what-you-use - A tool for use with clang to analyze #includes in C and C++ source files

# Взаимодействие Java и C/C++

#Java #C #Cplusplus #JNI #NativeCode #Programming #DevZone

6 min. reading
12 декабря 2017

Java, несмотря на некоторые «недостатки», является мощным и, что особенно важно, в большинстве случаев самодостаточным языком программирования. Под самодостаточностью я понимаю возможность писать программы, решающие конкретную задачу, без привлечения других языков программирования.

Однако я намеренно отметил, что самодостаточность Java проявляется именно в большинстве случаев. Иногда невозможно написать программу полностью, не используя вспомогательные инструменты. Например, может потребоваться код, обеспечивающий низкоуровневый доступ к «железу» компьютера, на котором выполняется программа. В языке Java, который изначально проектировался как кроссплатформенный, средства для низкоуровневого доступа к аппаратной части отсутствуют.

Для решения этой проблемы разработчики Java включили в язык возможность вызывать из Java-программ функции, реализованные на других языках программирования, через нативные методы. Подсистема Java, реализующая эту возможность, называется **JNI** (Java Native Interface — интерфейс Java для доступа к нативным методам).

Не так давно мне пришлось работать с одной Java-библиотекой. Проблема заключалась в том, что мне нужно было использовать методы, работающие с GPU (напишите в комментариях, если вам была бы интересна серия статей по CUDA), однако в Java-реализации библиотеки такой функциональности не было, и пришлось вызывать методы из программы на C. В этой статье мы поговорим о практическом применении #JNI.

## Создание класса

Для начала создадим класс, который будет содержать нативный метод.

```java
public class HelloJNI {
static {
System.loadLibrary("hello"); // Загрузка библиотеки hello.dll
}
// Объявление нативного метода sayHello(), без аргументов, возвращает void
private native void sayHello();
public static void main(String[] args) {
new HelloJNI().sayHello(); // вызов нативного метода
}
}
```

Мы объявили класс `HelloJNI`, содержащий нативный метод `sayHello`. Разберём код подробнее.

Блок `static` означает, что библиотека будет загружена во время загрузки класса. Чтобы программа смогла найти библиотеку, необходимо добавить путь к ней в `classpath`. Это можно сделать при запуске программы, добавив аргумент `-Djava.library.path=PATH_LIB`. Есть и другой вариант: вместо `loadLibrary` использовать `load`, но тогда придётся указывать полный путь к библиотеке (включая расширение `dll` или `so`).

На данном этапе у нас есть класс, но он никак не связан с библиотекой — самой библиотеки у нас пока нет.

## Создание библиотеки

Следующий шаг — компиляция файла и создание `h`-файла.

```bash
javac HelloJNI.java
javah HelloJNI
```

В результате мы получим следующий заголовочный файл:

```c
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloJNI */

#ifndef _Included_HelloJNI
#define _Included_HelloJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloJNI
* Method: sayHello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif
```

Что можно понять, глядя на этот файл? Во-первых, код на C будет подключать файл `jni.h`, который, к слову, содержит все необходимые функции для работы с JNI. Во-вторых, видно, что метод, описанный в классе `HelloJNI` как

```java
private native void sayHello();
```

в программе на C выглядит немного иначе:

```c
JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *, jobject);
```

Как видно, функция принимает два аргумента, хотя мы их явно не указывали. Что это за аргументы?

* `JNIEnv*` — указатель на JNI-окружение, предоставляющее доступ ко всем функциям JNI;
* `jobject` — указатель на объект `this` в Java.

Определение `JNIEXPORT` в файле `jni_md.h`, который подключается из `jni.h`, выглядит так:

```c
#define JNIEXPORT __declspec(dllexport)
```

А `JNICALL` там же определяется следующим образом:

```c
#define JNICALL __stdcall
```

После этого становится понятно, что все эти «страшные» конструкции — всего лишь соглашения, используемые при вызове обычной экспортируемой функции.

## Реализация на C

Теперь реализуем описанную функцию в `c`-файле.

```c
#include <jni.h>
#include <stdio.h>
#include "HelloJNI.h"

JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject thisObj) {
printf("Hello World!\n");
return;
}
```

Как видно, функция выводит строку в консоль и возвращает `void`. *Главное — не забыть подключить заголовочный файл, созданный ранее.* Файл `jni.h` находится в каталогах `JAVA_HOME\\include` и `JAVA_HOME\\include\\win32`.

Теперь можно скомпилировать файл:

```bash
gcc -Wl --add-stdcall-alias -I"%JAVA_HOME%\\include" -I"%JAVA_HOME%\\include\\win32" -shared -o hello.dll HelloJNI.c
```

Поясним параметры:

* `-Wl --add-stdcall-alias` — опция, предотвращающая возникновение ошибки линковщика (`UnsatisfiedLinkError`);
* `-I` — дополнительные пути для включаемых заголовков (в нашем случае — `jni.h`);
* `-shared` — генерация динамической библиотеки;
* `-o` — имя выходного файла.

Теперь можно запустить Java-программу:

```bash
java HelloJNI
Hello World!
```

*Если вы использовали метод `loadLibrary`, запускать программу нужно так:*

```bash
java -Djava.library.path=PATH_TO_LIB HelloJNI
Hello World!
```

## Заключение

В статье были рассмотрены общие принципы использования JNI. С помощью этой технологии можно также вызывать методы классов, создавать новые объекты, передавать различные параметры (массивы, строки и т. д.), возвращать значения и многое другое. Подробнее можно прочитать [в официальной документации Oracle] и [в практическом руководстве Javamex].

Использование нативных методов в Java нарушает принцип кроссплатформенности языка. Программа, использующая DLL, становится жёстко привязанной к платформе, под которую реализована эта библиотека. Нативные методы оправданы в случаях, когда основная Java-программа должна работать на разных платформах, а нативные части планируется разрабатывать отдельно для каждой из них. Если же программа предполагается к использованию только на одной платформе, возникает логичный вопрос: зачем тогда вообще кроссплатформенность?

Ещё один недостаток — из нативного метода можно получить доступ практически к любой части системы, что противоречит идеологии Java, где одним из ключевых требований является безопасность.

Тем не менее, несмотря на все минусы, выбор технологий всегда остаётся за программистом.

#JNI #JavaDevelopment #NativeMethods #CrossPlatform #SystemProgramming

This is probably my most used define in recent time:

#ifndef M_PI
#define M_PI 3.14159265358979323846f
#endif

@SRAZKVT @thephd @navi the other aspect is integrating into pkgconfig ecosystem, so you can write for example...

[[cfg::if(platform(unix))]]
using gtk-4.0;

instead of

#ifndef _WIN32
#include <gtk/gtk.h>
#endif

#ifndef INCLUDE_NOAI_H
#define INCLUDE_NOAI_H

#define gay auto
#define trans break
#define sex case
...

#endif

F-35 Fighter Jet's C++ Coding Standards [pdf]
----
- 15 minutes ago | 11 points | 2 comments
- URL: https://www.stroustrup.com/JSF-AV-rules.pdf
- Discussions: https://news.ycombinator.com/item?id=46185393
- Summary: LOCKHEED MARTIN’S JOINT STRIKE FIGHTER “2RDU00001 Rev C” DECEMBER 2005 C++ CODING STANDARDS
Purpose: Mandatory rules for safety-critical Air Vehicle software, extending MISRA-C concepts to C++.
Core Goals: Reliability, portability, maintainability, testability, reusability, extensibility, readability.
Key Constraints:
- Functions ≤ 200 logical lines, cyclomatic complexity ≤ 20.
- Strict subset of ISO C++ 2003; no trigraphs, digraphs, wide/multi-byte chars, errno, setjmp/longjmp, stdio, abort/exit, etc.
- Only four preprocessor directives allowed: #ifndef, #define, #endif, #include; no macro constants or inline macros—use const/inline functions.
- Headers *.h, implementations *.cpp; include guards mandatory; forward declarations to cut dependencies.
Style: 120-char lines, 2-space indent, no tabs, lowercase identifiers with underscores, public/protected/private order, braces required for all blocks.
Libraries: Only DO-178B level A certified or in-house safety-critical libraries.
Deviations: “Shall” rules require engineering & product-manager approval and inline documentation.