C++ è un linguaggio di programmazione multiparadigma con gestione manuale della memoria, che combina programmazione procedurale, orientata agli oggetti e generica. Nello sviluppo mobile, il C++ viene utilizzato tramite Android NDK per portare librerie e tramite i motori di gioco Unity e Unreal Engine per creare giochi multipiattaforma. Secondo TIOBE (2026), il C++ è tra i 5 linguaggi più popolari tra gli sviluppatori professionisti.
Punti chiave
C++ è un linguaggio di programmazione creato da Bjarne Stroustrup nel 1985 come estensione del linguaggio C con supporto alle classi. Il C++ fornisce accesso diretto alla memoria tramite puntatori, metaprogrammazione template e ereditarietà multipla. Gli standard C++17 e C++20 hanno aggiunto coroutine, concetti e ranges.
A differenza di Java e Kotlin, il C++ non ha un garbage collector — lo sviluppatore gestisce manualmente l'allocazione e la deallocazione della memoria tramite gli operatori new e delete. Questo dà il controllo totale sulle prestazioni ma richiede disciplina. Secondo il JetBrains Developer Survey (2025), il 42% degli sviluppatori C++ utilizza il linguaggio nell'industria dei giochi.
Gli standard C++ si evolvono ogni tre anni: C++11 (lambda, auto, unique_ptr), C++14 (lambda generiche), C++17 (if constexpr, filesystem), C++20 (moduli, coroutine, concetti). I compilatori Clang e GCC supportano tutti gli standard attuali, e Android NDK utilizza Clang dalla toolchain LLVM.
La differenza principale tra C++ e i linguaggi JVM è la gestione manuale della memoria e la compilazione diretta in codice macchina. Java e Kotlin funzionano su una macchina virtuale con garbage collection automatico. Il codice C++ viene compilato in un binario nativo per un'architettura specifica — ARM, x86 o RISC-V.
| Criterio | C++ | Java / Kotlin |
|---|---|---|
| Gestione memoria | Manuale (new/delete, RAII) | Automatica (Garbage Collector) |
| Compilazione | Codice macchina nativo | Bytecode JVM / ART |
| Prestazioni | Massime (zero-cost abstractions) | Alte con pause GC |
| Uso nello sviluppo mobile | NDK, giochi, librerie | App UI, logica di business |
| Build | CMake, NDK Build, Gradle + NDK | Gradle, Maven |
| Multipiattaforma | Compilare per ogni piattaforma | JVM / ART ovunque |
Android NDK (Native Development Kit) è un kit di strumenti di Google per scrivere parti di applicazioni Android in C e C++. L'NDK include una toolchain basata su Clang, file di intestazione del sistema Android e librerie di debugging e profiling. La versione r27 (2025) supporta C++20 e utilizza LLVM 18.
L'NDK compila codice C++ in librerie dinamiche .so per le architetture ARM64, ARM32, x86 e x86_64. Un'applicazione Java o Kotlin carica queste librerie tramite System.loadLibrary() e chiama funzioni native tramite JNI. Secondo Google, l'NDK è stato scaricato oltre 5 milioni di volte.
Un progetto tipico con Android NDK contiene la cartella app/src/main/cpp/ con file sorgente C++, CMakeLists.txt per la build e una classe Java con dichiarazione di metodi nativi. Gradle collega l'NDK tramite il blocco externalNativeBuild in build.gradle.
// native-lib.cpp — semplice metodo JNI per Android
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_app_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /*thiz*/) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}Il codice dichiara una funzione JNI con il nome completo Java_com_example_app_MainActivity_stringFromJNI — questa è la convenzione di denominazione JNI. La funzione accetta un puntatore a JNIEnv (l'ambiente di esecuzione) e jobject (l'istanza della classe chiamante). env->NewStringUTF crea una stringa Java da una stringa C++.
Android supporta diversi ABI (Application Binary Interface): arm64-v8a (dispositivi ARM a 64 bit, 99% degli smartphone moderni), armeabi-v7a (ARM a 32 bit, dispositivi legacy), x86_64 (emulatori). L'NDK consente di compilare .so per ogni architettura tramite filtri ABI in build.gradle.
android {
defaultConfig {
ndk {
abiFilters "arm64-v8a", "armeabi-v7a"
}
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.22.1"
}
}
}C++ è il linguaggio principale dei motori di gioco. Unreal Engine utilizza C++ per tutto il codice del gioco, mentre Unity usa C++ nel core del motore per rendering e fisica. Anche se uno sviluppatore scrive in C# in Unity, sotto il cofano C++ gestisce grafica, suono e calcoli fisici.
Unreal Engine è costruito su C++ da zero. Il codice della logica di gioco è scritto in C++ utilizzando macro UHT (Unreal Header Tool) per l'integrazione con Blueprints — un sistema di scripting visivo. Le classi ereditano dai tipi base AActor, UObject, UGameInstance con lettere di prefisso U, A, F.
// Classe personaggio in Unreal Engine con C++
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "MyCharacter.generated.h"
UCLASS()
class AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
AMyCharacter();
virtual void BeginPlay() override;
virtual void Tick(float DeltaTime) override;
UPROPERTY(EditAnywhere, Category = "Movement")
float MoveSpeed = 600.0f;
protected:
void SetupPlayerInputComponent(UInputComponent *PlayerInputComponent) override;
};Le macro UCLASS() e UPROPERTY() fanno parte del sistema di reflection di Unreal Engine. UHT (Unreal Header Tool) genera codice C++ dai file di intestazione per serializzazione, blueprint e replicazione di rete. MoveSpeed viene visualizzato nell'editor tramite UPROPERTY(EditAnywhere).
Unity usa C# per la logica di gioco, ma C++ viene utilizzato nei plugin nativi — librerie .so per Android e .bundle per iOS. Tramite Android NDK è possibile integrare SDK C++ per reti pubblicitarie, analisi o portare librerie C++ da giochi desktop.
using System.Runtime.InteropServices;
using UnityEngine;
public class NativeBridge : MonoBehaviour
{
const string LIB_NAME = "native_plugin";
[DllImport(LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
private static extern int ProcessFrame(
int width, int height,
IntPtr pixelData
);
void Update()
{
int result = ProcessFrame(Screen.width, Screen.height, IntPtr.Zero);
Debug.Log("Frame processed: " + result);
}
}In questo esempio, C# effettua il marshaling di una chiamata alla funzione C++ ProcessFrame tramite P/Invoke. L'attributo DllImport specifica il nome della libreria .so. La funzione C++ elabora il frame in tempo reale e restituisce il risultato. Questo approccio viene utilizzato per post-effetti e visione artificiale.
JNI (Java Native Interface) è il meccanismo standard per chiamare codice C/C++ da Java o Kotlin. In Android, JNI è l'unico modo per trasferire dati tra la macchina virtuale ART e una libreria nativa. Ogni chiamata JNI ha un overhead, quindi i dati dovrebbero essere trasferiti in lotti invece che un campo alla volta.
JNIEnv è un puntatore alla tabella delle funzioni JNI. env->FindClass carica una classe Java, env->GetMethodID ottiene un identificatore di metodo, env->CallVoidMethod lo invoca. Per le stringhe, utilizzare GetStringUTFChars e ReleaseStringUTFChars. JNI supporta anche riferimenti globali e deboli a oggetti Java.
// Passare array di byte da C++ a Java tramite JNI
extern "C" JNIEXPORT void JNICALL
Java_com_example_app_ImageProcessor_processArray(
JNIEnv *env, jobject /*thiz*/,
jbyteArray input, jint length) {
jbyte *buffer = env->GetByteArrayElements(input, nullptr);
jsize size = env->GetArrayLength(input);
for (jsize i = 0; i < size; ++i) {
buffer[i] = buffer[i] ^ 0xFF; // invertire byte
}
env->ReleaseByteArrayElements(input, buffer, JNI_COMMIT);
}GetByteArrayElements ottiene un puntatore all'array di byte Java. JNI_COMMIT in ReleaseByteArrayElements copia le modifiche nell'array Java senza liberare memoria. L'elaborazione del ciclo for viene eseguita sulla CPU con massime prestazioni C++ senza pause GC.
Il pericolo principale di JNI sono le perdite di riferimenti globali. Ogni NewGlobalRef deve essere liberato tramite DeleteGlobalRef. I riferimenti locali (restituiti da FindClass, NewStringUTF) vengono automaticamente rilasciati al ritorno dalla funzione nativa. Per chiamate intensive, utilizzare PushLocalFrame / PopLocalFrame.
CMake è lo strumento di build principale per C++ in Android NDK. CMakeLists.txt descrive i target di build, le librerie e le dipendenze. Gradle invoca CMake tramite externalNativeBuild, passando i percorsi all'NDK e alla toolchain. Un'alternativa è NDK Build basato su Android.mk e Application.mk.
CMake 3.22+ supporta preset (CMakePresets.json) per diverse configurazioni: debug, release, profile con diversi flag di ottimizzazione. Per Android, viene utilizzata la toolchain android.toolchain.cmake dall'NDK, fornita automaticamente da Gradle durante la build.
# CMakeLists.txt per progetto Android NDK
cmake_minimum_required(VERSION 3.22)
project("native-lib")
add_library(
native-lib
SHARED
src/main/cpp/native-lib.cpp
src/main/cpp/image_utils.cpp
)
target_include_directories(
native-lib PRIVATE
src/main/cpp/include
)
target_link_libraries(
native-lib
android
log
${CMAKE_SOURCE_DIR}/libs/libjpeg.a
)
set_target_properties(
native-lib PROPERTIES
CXX_STANDARD 20
CXX_STANDARD_REQUIRED ON
)add_library(SHARED) crea una libreria .so. target_link_libraries collega le librerie di sistema android (per JNI) e log (per __android_log_print). La libreria statica libjpeg.a viene collegata per l'elaborazione di immagini JPEG. CXX_STANDARD 20 abilita il supporto C++20.
vcpkg è un gestore di pacchetti C++ di Microsoft che supporta Android NDK come piattaforma target. Tramite vcpkg si possono installare Boost, OpenCV, SQLite, nlohmann-json e altre librerie compilate per Android ABI. Vcpkg si integra con CMake tramite CMAKE_TOOLCHAIN_FILE.
C++ offre prestazioni massime sui dispositivi mobili grazie alla compilazione in codice ARM nativo e all'assenza di garbage collector. Secondo i test di Google (Android Performance Patterns, 2024), il codice JNI in C++ viene eseguito da 3 a 10 volte più velocemente del codice Java equivalente per attività con calcoli intensivi.
Fattori chiave delle prestazioni C++ su piattaforme mobili: località della cache (disposizione contigua della memoria), istruzioni SIMD NEON per ARM, comunicazione JNI asincrona tramite code di messaggi. NEON è l'estensione SIMD di ARM, che elabora 128 bit di dati in una singola istruzione, indispensabile per l'elaborazione di audio, video e immagini.
// Elaborazione SIMD di array tramite NEON intrinsics
#include <arm_neon.h>
void process_audio_neon(float *data, size_t n) {
for (size_t i = 0; i < n; i += 4) {
float32x4_t vec = vld1q_f32(&data[i]);
float32x4_t result = vmulq_f32(vec, vdupq_n_f32(0.5f));
vst1q_f32(&data[i], result);
}
}vld1q_f32 carica 4 float dalla memoria in un registro NEON a 128 bit. vmulq_f32 moltiplica tutti i 4 elementi per 0.5 in un ciclo. vst1q_f32 memorizza il risultato. Senza SIMD, lo stesso ciclo eseguirebbe 4 moltiplicazioni sequenziali — NEON offre fino a 4x di accelerazione per tali operazioni.
| Operazione | C++ (ms) | Java/Kotlin (ms) | Accelerazione |
|---|---|---|---|
| Elaborazione immagine 1920x1080 | 12 | 45 | 3.75x |
| Trasformata di Fourier veloce (FFT) | 8 | 34 | 4.25x |
| Crittografia AES-256 di blocco 1MB | 3 | 18 | 6x |
| Compressione dati ZLIB | 5 | 22 | 4.4x |
Il primo e più pericoloso errore sono le perdite di memoria. Ogni new deve avere un delete, ogni new[] deve avere un delete[]. Sui dispositivi mobili con RAM limitata, qualsiasi perdita porta a OOM (Out Of Memory) e al crash dell'app. Utilizzare RAII tramite puntatori intelligenti: std::unique_ptr, std::shared_ptr, std::weak_ptr.
Il secondo errore è ignorare la compatibilità ABI. Una libreria compilata per armeabi-v7a non si caricherà su un dispositivo ARM64. Specificare sempre abiFilters in build.gradle e testare su dispositivi reali, non solo sull'emulatore x86_64. Utilizzare Android App Bundle per il filtraggio automatico ABI.
Il terzo errore comune sono le chiamate JNI frequenti. Ogni transizione tra Java e C++ costa circa 50–100 ns. Se si elabora un array di 10000 elementi uno per uno tramite JNI, l'overhead supera il lavoro utile. Passare interi array in una volta e elaborarli lato C++.
Problemi di threading sono un altro errore frequente. C++ può avviare std::thread, ma JNI è accessibile solo da thread creati da Java. Per chiamare metodi Java da un thread C++, utilizzare AttachCurrentThread / DetachCurrentThread tramite JNI.
// Chiamare Java correttamente da un thread C++
JavaVM *g_vm; // puntatore globale ottenuto in JNI_OnLoad
void background_task() {
JNIEnv *env;
jint res = g_vm->AttachCurrentThread(&env, nullptr);
if (res == JNI_OK) {
jclass clazz = env->FindClass("com/example/App");
jmethodID mid = env->GetStaticMethodID(clazz, "onProgress", "(I)V");
env->CallStaticVoidMethod(clazz, mid, 100);
g_vm->DetachCurrentThread();
}
}Domande frequenti
Android NDK (Native Development Kit) è un kit di strumenti per scrivere parti di applicazioni in C o C++. Viene utilizzato per attività critiche per le prestazioni, portare librerie C/C++ su Android e implementare codice multipiattaforma per Unity e Unreal Engine.
In Unity, il codice della logica di gioco è scritto in C#, ma C++ viene utilizzato insieme ad Android NDK per plugin, accelerazione hardware, portare librerie C++ personalizzate e integrare SDK nativi per pubblicità e analisi.
CMakeLists.txt descrive file sorgente, librerie e flag di compilazione. La configurazione minima include add_library per compilare .so e target_link_libraries per collegare il log di Android e altre librerie di sistema.
JNI (Java Native Interface) è il livello tra il codice Java/Kotlin di un'app Android e la libreria C++. Se C++ viene chiamato da Java, JNI è obbligatorio. Si può scrivere codice C++ interamente tramite NDK, ma il punto di ingresso è solitamente una Activity Java che chiama funzioni native.
C++ è giustificato per giochi, elaborazione audio/video in tempo reale, visione artificiale, crittografia, simulazioni fisiche e portare librerie da altre piattaforme. Per un'applicazione UI normale, Kotlin è più efficiente e semplice.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.