C++ nello sviluppo mobile: Android NDK, Unity e Unreal Engine

Autore: IT Sectr Pubblicato: 2026-02-10 Tempo di lettura: 11 min

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 di sistema utilizzato in Android NDK, Unity e Unreal Engine
  • Android NDK consente di compilare codice C++ in librerie native .so per processori ARM
  • Unreal Engine è interamente costruito su C++, mentre Unity usa C++ per plugin di basso livello
  • JNI (Java Native Interface) è il ponte tra Java/Kotlin e C++ su Android
  • CMake e NDK Build sono i sistemi di build per progetti C++ su piattaforme mobili

Cos'è il C++?

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.

Differenze tra C++ e Java/Kotlin

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.

CriterioC++Java / Kotlin
Gestione memoriaManuale (new/delete, RAII)Automatica (Garbage Collector)
CompilazioneCodice macchina nativoBytecode JVM / ART
PrestazioniMassime (zero-cost abstractions)Alte con pause GC
Uso nello sviluppo mobileNDK, giochi, librerieApp UI, logica di business
BuildCMake, NDK Build, Gradle + NDKGradle, Maven
MultipiattaformaCompilare per ogni piattaformaJVM / ART ovunque

C++ nello sviluppo mobile: Android NDK

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.

Struttura del progetto con NDK

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.

cpp
// 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++.

ABI e architetture target

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.

gradle
android {
    defaultConfig {
        ndk {
            abiFilters "arm64-v8a", "armeabi-v7a"
        }
    }
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.22.1"
        }
    }
}

C++ e motori di gioco: Unity e Unreal Engine

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: C++ come linguaggio principale

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.

cpp
// 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: C++ in plugin e SDK nativi

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.

csharp
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: interazione tra Java e C++

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.

cpp
// 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.

Gestione della memoria in JNI

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 e sistemi di build per C++ su Android

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.

cmake
# 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 e gestione delle dipendenze

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.

Prestazioni del C++ sui dispositivi mobili

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.

cpp
// 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.

OperazioneC++ (ms)Java/Kotlin (ms)Accelerazione
Elaborazione immagine 1920x108012453.75x
Trasformata di Fourier veloce (FFT)8344.25x
Crittografia AES-256 di blocco 1MB3186x
Compressione dati ZLIB5224.4x

Errori comuni nell'uso del C++ nei progetti mobili

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.

cpp
// 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

Cos'è Android NDK e perché serve C++ al suo interno?

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.

Quali giochi Unity sono scritti in C++?

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.

Come configurare CMakeLists.txt per C++ su Android?

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 in C++ è obbligatorio per Android?

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.

Quando il C++ è giustificato invece di Kotlin nello sviluppo mobile?

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

  • C++ è un linguaggio multiparadigma con gestione manuale della memoria, utilizzato in Android NDK, Unity e Unreal Engine per codice ad alte prestazioni
  • Android NDK compila C++ in librerie .so per architetture ARM con la toolchain Clang di LLVM
  • Unreal Engine è interamente costruito su C++ con il sistema di reflection UHT, Unity usa C++ nel suo core di rendering e fisica
  • JNI è il ponte obbligatorio tra Java/Kotlin e C++ su Android con la convenzione Java___
  • CMake è il sistema di build principale per C++ in NDK, con supporto C++20 e integrazione Gradle
  • NEON SIMD offre fino a 4x di accelerazione nell'elaborazione dati su processori ARM tramite istruzioni vettoriali a 128 bit
  • Errori comuni: perdite di memoria, ABI errato in abiFilters, chiamate JNI frequenti e threading senza AttachCurrentThread

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.

Discuti il progetto

Leggi anche