This archive contains answers to questions sent to Unidata support through mid-2025. Note that the archive is no longer being updated. We provide the archive for reference; many of the answers presented here remain technically correct, even if somewhat outdated. For the most up-to-date information on the use of NSF Unidata software and data services, please consult the Software Documentation first.
Mike, I've attached the netcdfcpp.h and the ncvalues.h file it also requires. I don't think we have a Windows .lib or .dll with the C++ interface built, but I've Cc:ed Ed in case he knows of one. --Russ Russ Rew UCAR Unidata Program address@hidden http://www.unidata.ucar.edu Ticket Details =================== Ticket ID: XLE-835004 Department: Support netCDF Priority: Normal Status: Closed
/********************************************************************* * Copyright 1992, University Corporation for Atmospheric Research * See netcdf/README file for copying and redistribution conditions. * * Purpose: interface for classes of typed arrays for netCDF * * $Header: /upc/share/CVS/netcdf-3/cxx/ncvalues.h,v 1.7 2006/07/26 21:12:06 russ Exp $ *********************************************************************/ #ifndef Ncvalues_def #define Ncvalues_def #include <iostream> #include <sstream> #include <limits.h> #include "netcdf.h" // Documentation warned this might change and now it has, for // consistency with C interface typedef signed char ncbyte; #define NC_UNSPECIFIED ((nc_type)0) // C++ interface dates from before netcdf-3, still uses some netcdf-2 names #ifdef NO_NETCDF_2 #define NC_LONG NC_INT #define FILL_LONG NC_FILL_INT typedef int nclong; #define NC_FATAL 1 #define NC_VERBOSE 2 #endif enum NcType { ncNoType = NC_UNSPECIFIED, ncByte = NC_BYTE, ncChar = NC_CHAR, ncShort = NC_SHORT, ncInt = NC_INT, ncLong = NC_LONG, // deprecated, someday want to use for 64-bit ints ncFloat = NC_FLOAT, ncDouble = NC_DOUBLE }; #define ncBad_ncbyte ncBad_byte static const ncbyte ncBad_byte = NC_FILL_BYTE; static const char ncBad_char = NC_FILL_CHAR; static const short ncBad_short = NC_FILL_SHORT; static const nclong ncBad_nclong = FILL_LONG; // deprecated static const int ncBad_int = NC_FILL_INT; static const long ncBad_long = FILL_LONG; // deprecated static const float ncBad_float = NC_FILL_FLOAT; static const double ncBad_double = NC_FILL_DOUBLE; // macros to glue tokens together to form new names (used to be in generic.h) #define name2(a,b) a ## b #define declare(clas,t) name2(clas,declare)(t) #define implement(clas,t) name2(clas,implement)(t) // This is the same as the name2 macro, but we need to define our own // version since rescanning something generated with the name2 macro // won't necessarily cause name2 to be expanded again. #define makename2(z, y) makename2_x(z, y) #define makename2_x(z, y) z##y #define NcVal(TYPE) makename2(NcValues_,TYPE) #define NcValuesdeclare(TYPE) \ class NcVal(TYPE) : public NcValues \ { \ public: \ NcVal(TYPE)( void ); \ NcVal(TYPE)(long num); \ NcVal(TYPE)(long num, const TYPE* vals); \ NcVal(TYPE)(const NcVal(TYPE)&); \ virtual NcVal(TYPE)& operator=(const NcVal(TYPE)&); \ virtual ~NcVal(TYPE)( void ); \ virtual void* base( void ) const; \ virtual int bytes_for_one( void ) const; \ virtual ncbyte as_ncbyte( long n ) const; \ virtual char as_char( long n ) const; \ virtual short as_short( long n ) const; \ virtual int as_int( long n ) const; \ virtual int as_nclong( long n ) const; \ virtual long as_long( long n ) const; \ virtual float as_float( long n ) const; \ virtual double as_double( long n ) const; \ virtual char* as_string( long n ) const; \ virtual int invalid( void ) const; \ private: \ TYPE* the_values; \ std::ostream& print(std::ostream&) const; \ }; #define NcTypeEnum(TYPE) makename2(_nc__,TYPE) #define _nc__ncbyte ncByte #define _nc__char ncChar #define _nc__short ncShort #define _nc__int ncInt #define _nc__nclong ncLong #define _nc__long ncLong #define _nc__float ncFloat #define _nc__double ncDouble #define NcValuesimplement(TYPE) \ NcVal(TYPE)::NcVal(TYPE)( void ) \ : NcValues(NcTypeEnum(TYPE), 0), the_values(0) \ {} \ \ NcVal(TYPE)::NcVal(TYPE)(long num, const TYPE* vals) \ : NcValues(NcTypeEnum(TYPE), num) \ { \ the_values = new TYPE[num]; \ for(int i = 0; i < num; i++) \ the_values[i] = vals[i]; \ } \ \ NcVal(TYPE)::NcVal(TYPE)(long num) \ : NcValues(NcTypeEnum(TYPE), num), the_values(new TYPE[num]) \ {} \ \ NcVal(TYPE)::NcVal(TYPE)(const NcVal(TYPE)& v) : \ NcValues(v) \ { \ delete[] the_values; \ the_values = new TYPE[v.the_number]; \ for(int i = 0; i < v.the_number; i++) \ the_values[i] = v.the_values[i]; \ } \ \ NcVal(TYPE)& NcVal(TYPE)::operator=(const NcVal(TYPE)& v) \ { \ if ( &v != this) { \ NcValues::operator=(v); \ delete[] the_values; \ the_values = new TYPE[v.the_number]; \ for(int i = 0; i < v.the_number; i++) \ the_values[i] = v.the_values[i]; \ } \ return *this; \ } \ \ void* NcVal(TYPE)::base( void ) const \ { \ return the_values; \ } \ \ NcVal(TYPE)::~NcVal(TYPE)( void ) \ { \ delete[] the_values; \ } \ \ int NcVal(TYPE)::invalid( void ) const \ { \ for(int i=0;i<the_number;i++) \ if (the_values[i] == makename2(ncBad_,TYPE)) return 1; \ return 0; \ } \ #define Ncbytes_for_one_implement(TYPE) \ int NcVal(TYPE)::bytes_for_one( void ) const \ { \ return sizeof(TYPE); \ } #define as_ncbyte_implement(TYPE) \ ncbyte NcVal(TYPE)::as_ncbyte( long n ) const \ { \ if (the_values[n] < 0 || the_values[n] > UCHAR_MAX) \ return ncBad_byte; \ return (ncbyte) the_values[n]; \ } #define as_char_implement(TYPE) \ char NcVal(TYPE)::as_char( long n ) const \ { \ if (the_values[n] < CHAR_MIN || the_values[n] > CHAR_MAX) \ return ncBad_char; \ return (char) the_values[n]; \ } #define as_short_implement(TYPE) \ short NcVal(TYPE)::as_short( long n ) const \ { \ if (the_values[n] < SHRT_MIN || the_values[n] > SHRT_MAX) \ return ncBad_short; \ return (short) the_values[n]; \ } #define NCINT_MIN INT_MIN #define NCINT_MAX INT_MAX #define as_int_implement(TYPE) \ int NcVal(TYPE)::as_int( long n ) const \ { \ if (the_values[n] < NCINT_MIN || the_values[n] > NCINT_MAX) \ return ncBad_int; \ return (int) the_values[n]; \ } #define NCLONG_MIN INT_MIN #define NCLONG_MAX INT_MAX #define as_nclong_implement(TYPE) \ nclong NcVal(TYPE)::as_nclong( long n ) const \ { \ if (the_values[n] < NCLONG_MIN || the_values[n] > NCLONG_MAX) \ return ncBad_nclong; \ return (nclong) the_values[n]; \ } #define as_long_implement(TYPE) \ long NcVal(TYPE)::as_long( long n ) const \ { \ if (the_values[n] < LONG_MIN || the_values[n] > LONG_MAX) \ return ncBad_long; \ return (long) the_values[n]; \ } #define as_float_implement(TYPE) \ inline float NcVal(TYPE)::as_float( long n ) const \ { \ return (float) the_values[n]; \ } #define as_double_implement(TYPE) \ inline double NcVal(TYPE)::as_double( long n ) const \ { \ return (double) the_values[n]; \ } #define as_string_implement(TYPE) \ char* NcVal(TYPE)::as_string( long n ) const \ { \ char* s = new char[32]; \ std::ostringstream ostr; \ ostr << the_values[n]; \ ostr.str().copy(s, std::string::npos); \ s[ostr.str().length()] = 0; \ return s; \ } class NcValues // ABC for value blocks { public: NcValues( void ); NcValues(NcType, long); virtual ~NcValues( void ); virtual long num( void ); virtual std::ostream& print(std::ostream&) const = 0; virtual void* base( void ) const = 0; virtual int bytes_for_one( void ) const = 0; // The following member functions provide conversions from the value // type to a desired basic type. If the value is out of range, the // default "fill-value" for the appropriate type is returned. virtual ncbyte as_ncbyte( long n ) const = 0; // nth value as a byte virtual char as_char( long n ) const = 0; // nth value as char virtual short as_short( long n ) const = 0; // nth value as short virtual int as_int( long n ) const = 0; // nth value as int virtual int as_nclong( long n ) const = 0; // nth value as nclong virtual long as_long( long n ) const = 0; // nth value as long virtual float as_float( long n ) const = 0; // nth value as floating-point virtual double as_double( long n ) const = 0; // nth value as double virtual char* as_string( long n ) const = 0; // value as string protected: NcType the_type; long the_number; friend std::ostream& operator<< (std::ostream&, const NcValues&); }; declare(NcValues,ncbyte) declare(NcValues,char) declare(NcValues,short) declare(NcValues,int) declare(NcValues,nclong) declare(NcValues,long) declare(NcValues,float) declare(NcValues,double) #endif
/********************************************************************* * Copyright 1992, University Corporation for Atmospheric Research * See netcdf/README file for copying and redistribution conditions. * * Purpose: C++ class interface for netCDF * * $Header: /upc/share/CVS/netcdf-3/cxx/netcdfcpp.h,v 1.14 2006/07/31 20:42:48 russ Exp $ *********************************************************************/ #ifndef NETCDF_HH #define NETCDF_HH #include "ncvalues.h" // arrays that know their element type typedef const char* NcToken; // names for netCDF objects typedef unsigned int NcBool; // many members return 0 on failure class NcDim; // dimensions class NcVar; // variables class NcAtt; // attributes /* * *********************************************************************** * A netCDF file. * *********************************************************************** */ class NcFile { public: virtual ~NcFile( void ); enum FileMode { ReadOnly, // file exists, open read-only Write, // file exists, open for writing Replace, // create new file, even if already exists New // create new file, fail if already exists }; enum FileFormat { Classic, // netCDF classic format (i.e. version 1 format) Offset64Bits, // netCDF 64-bit offset format Netcdf4, // netCDF-4 using HDF5 format Netcdf4Classic, // netCDF-4 using HDF5 format using only netCDF-3 calls BadFormat }; NcFile( const char * path, FileMode = ReadOnly , size_t *chunksizeptr = NULL, // optional tuning parameters size_t initialsize = 0, FileFormat = Classic ); NcBool is_valid( void ) const; // opened OK in ctr, still valid int num_dims( void ) const; // number of dimensions int num_vars( void ) const; // number of variables int num_atts( void ) const; // number of (global) attributes NcDim* get_dim( NcToken ) const; // dimension by name NcVar* get_var( NcToken ) const; // variable by name NcAtt* get_att( NcToken ) const; // global attribute by name NcDim* get_dim( int ) const; // n-th dimension NcVar* get_var( int ) const; // n-th variable NcAtt* get_att( int ) const; // n-th global attribute NcDim* rec_dim( void ) const; // unlimited dimension, if any // Add new dimensions, variables, global attributes. // These put the file in "define" mode, so could be expensive. virtual NcDim* add_dim( NcToken dimname, long dimsize ); virtual NcDim* add_dim( NcToken dimname ); // unlimited virtual NcVar* add_var( NcToken varname, NcType type, // scalar const NcDim* dim0=0, // 1-dim const NcDim* dim1=0, // 2-dim const NcDim* dim2=0, // 3-dim const NcDim* dim3=0, // 4-dim const NcDim* dim4=0 ); // 5-dim virtual NcVar* add_var( NcToken varname, NcType type, // n-dim int ndims, const NcDim** dims ); NcBool add_att( NcToken attname, char ); // scalar attributes NcBool add_att( NcToken attname, ncbyte ); NcBool add_att( NcToken attname, short ); NcBool add_att( NcToken attname, long ); NcBool add_att( NcToken attname, int ); NcBool add_att( NcToken attname, float ); NcBool add_att( NcToken attname, double ); NcBool add_att( NcToken attname, const char*); // string attribute NcBool add_att( NcToken attname, int, const char* ); // vector attributes NcBool add_att( NcToken attname, int, const ncbyte* ); NcBool add_att( NcToken attname, int, const short* ); NcBool add_att( NcToken attname, int, const long* ); NcBool add_att( NcToken attname, int, const int* ); NcBool add_att( NcToken attname, int, const float* ); NcBool add_att( NcToken attname, int, const double* ); enum FillMode { Fill = NC_FILL, // prefill (default) NoFill = NC_NOFILL, // don't prefill Bad }; NcBool set_fill( FillMode = Fill ); // set fill-mode FillMode get_fill( void ) const; // get fill-mode FileFormat get_format( void ) const; // get format version NcBool sync( void ); // synchronize to disk NcBool close( void ); // to close earlier than dtr NcBool abort( void ); // back out of bad defines // Needed by other Nc classes, but users will not need them NcBool define_mode( void ); // leaves in define mode, if possible NcBool data_mode( void ); // leaves in data mode, if possible int id( void ) const; // id used by C interface protected: int the_id; int in_define_mode; FillMode the_fill_mode; NcDim** dimensions; NcVar** variables; NcVar* globalv; // "variable" for global attributes }; /* * For backward compatibility. We used to derive NcOldFile and NcNewFile * from NcFile, but that was over-zealous inheritance. */ #define NcOldFile NcFile #define NcNewFile NcFile #define Clobber Replace #define NoClobber New /* * ********************************************************************** * A netCDF dimension, with a name and a size. These are only created * by NcFile member functions, because they cannot exist independently * of an open netCDF file. * ********************************************************************** */ class NcDim { public: NcToken name( void ) const; long size( void ) const; NcBool is_valid( void ) const; NcBool is_unlimited( void ) const; NcBool rename( NcToken newname ); int id( void ) const; NcBool sync( void ); private: NcFile *the_file; // not const because of rename int the_id; char *the_name; NcDim(NcFile*, int num); // existing dimension NcDim(NcFile*, NcToken name, long sz); // defines a new dim virtual ~NcDim( void ); // to construct dimensions, since constructor is private friend class NcFile; }; /* * ********************************************************************** * Abstract base class for a netCDF variable or attribute, both of which * have a name, a type, and associated values. These only exist as * components of an open netCDF file. * ********************************************************************** */ class NcTypedComponent { public: virtual ~NcTypedComponent( void ) {} virtual NcToken name( void ) const = 0; virtual NcType type( void ) const = 0; virtual NcBool is_valid( void ) const = 0; virtual long num_vals( void ) const = 0; virtual NcBool rename( NcToken newname ) = 0; virtual NcValues* values( void ) const = 0; // block of all values // The following member functions provide conversions from the value // type to a desired basic type. If the value is out of range, // the default "fill-value" for the appropriate type is returned. virtual ncbyte as_ncbyte( long n ) const; // nth value as an unsgnd char virtual char as_char( long n ) const; // nth value as char virtual short as_short( long n ) const; // nth value as short virtual int as_int( long n ) const; // nth value as int virtual int as_nclong( long n ) const; // nth value as nclong (deprecated) virtual long as_long( long n ) const; // nth value as long virtual float as_float( long n ) const; // nth value as floating-point virtual double as_double( long n ) const; // nth value as double virtual char* as_string( long n ) const; // nth value as string protected: NcFile *the_file; NcTypedComponent( NcFile* ); virtual NcValues* get_space( long numVals = 0 ) const; // to hold values }; /* * ********************************************************************** * netCDF variables. In addition to a name and a type, these also have * a shape, given by a list of dimensions * ********************************************************************** */ class NcVar : public NcTypedComponent { public: virtual ~NcVar( void ); NcToken name( void ) const; NcType type( void ) const; NcBool is_valid( void ) const; int num_dims( void ) const; // dimensionality of variable NcDim* get_dim( int ) const; // n-th dimension long* edges( void ) const; // dimension sizes int num_atts( void ) const; // number of attributes NcAtt* get_att( NcToken ) const; // attribute by name NcAtt* get_att( int ) const; // n-th attribute long num_vals( void ) const; // product of dimension sizes NcValues* values( void ) const; // all values // Put scalar or 1, ..., 5 dimensional arrays by providing enough // arguments. Arguments are edge lengths, and their number must not // exceed variable's dimensionality. Start corner is [0,0,..., 0] by // default, but may be reset using the set_cur() member. FALSE is // returned if type of values does not match type for variable. NcBool put( const ncbyte* vals, long c0=0, long c1=0, long c2=0, long c3=0, long c4=0 ); NcBool put( const char* vals, long c0=0, long c1=0, long c2=0, long c3=0, long c4=0 ); NcBool put( const short* vals, long c0=0, long c1=0, long c2=0, long c3=0, long c4=0 ); NcBool put( const int* vals, long c0=0, long c1=0, long c2=0, long c3=0, long c4=0 ); NcBool put( const long* vals, long c0=0, long c1=0, long c2=0, long c3=0, long c4=0 ); NcBool put( const float* vals, long c0=0, long c1=0, long c2=0, long c3=0, long c4=0 ); NcBool put( const double* vals, long c0=0, long c1=0, long c2=0, long c3=0, long c4=0 ); // Put n-dimensional arrays, starting at [0, 0, ..., 0] by default, // may be reset with set_cur(). NcBool put( const ncbyte* vals, const long* counts ); NcBool put( const char* vals, const long* counts ); NcBool put( const short* vals, const long* counts ); NcBool put( const int* vals, const long* counts ); NcBool put( const long* vals, const long* counts ); NcBool put( const float* vals, const long* counts ); NcBool put( const double* vals, const long* counts ); // Get scalar or 1, ..., 5 dimensional arrays by providing enough // arguments. Arguments are edge lengths, and their number must not // exceed variable's dimensionality. Start corner is [0,0,..., 0] by // default, but may be reset using the set_cur() member. NcBool get( ncbyte* vals, long c0=0, long c1=0, long c2=0, long c3=0, long c4=0 ) const; NcBool get( char* vals, long c0=0, long c1=0, long c2=0, long c3=0, long c4=0 ) const; NcBool get( short* vals, long c0=0, long c1=0, long c2=0, long c3=0, long c4=0 ) const; NcBool get( int* vals, long c0=0, long c1=0, long c2=0, long c3=0, long c4=0 ) const; NcBool get( long* vals, long c0=0, long c1=0, long c2=0, long c3=0, long c4=0 ) const; NcBool get( float* vals, long c0=0, long c1=0, long c2=0, long c3=0, long c4=0 ) const; NcBool get( double* vals, long c0=0, long c1=0, long c2=0, long c3=0, long c4=0 ) const; // Get n-dimensional arrays, starting at [0, 0, ..., 0] by default, // may be reset with set_cur(). NcBool get( ncbyte* vals, const long* counts ) const; NcBool get( char* vals, const long* counts ) const; NcBool get( short* vals, const long* counts ) const; NcBool get( int* vals, const long* counts ) const; NcBool get( long* vals, const long* counts ) const; NcBool get( float* vals, const long* counts ) const; NcBool get( double* vals, const long* counts ) const; NcBool set_cur(long c0=-1, long c1=-1, long c2=-1, long c3=-1, long c4=-1); NcBool set_cur(long* cur); // these put file in define mode, so could be expensive NcBool add_att( NcToken, char ); // add scalar attributes NcBool add_att( NcToken, ncbyte ); NcBool add_att( NcToken, short ); NcBool add_att( NcToken, int ); NcBool add_att( NcToken, long ); NcBool add_att( NcToken, float ); NcBool add_att( NcToken, double ); NcBool add_att( NcToken, const char* ); // string attribute NcBool add_att( NcToken, int, const char* ); // vector attributes NcBool add_att( NcToken, int, const ncbyte* ); NcBool add_att( NcToken, int, const short* ); NcBool add_att( NcToken, int, const int* ); NcBool add_att( NcToken, int, const long* ); NcBool add_att( NcToken, int, const float* ); NcBool add_att( NcToken, int, const double* ); NcBool rename( NcToken newname ); long rec_size ( void ); // number of values per record long rec_size ( NcDim* ); // number of values per dimension slice // Though following are intended for record variables, they also work // for other variables, using first dimension as record dimension. // Get a record's worth of data NcValues *get_rec(void); // get current record NcValues *get_rec(long rec); // get specified record NcValues *get_rec(NcDim* d); // get current dimension slice NcValues *get_rec(NcDim* d, long slice); // get specified dimension slice // Put a record's worth of data in current record NcBool put_rec( const ncbyte* vals ); NcBool put_rec( const char* vals ); NcBool put_rec( const short* vals ); NcBool put_rec( const int* vals ); NcBool put_rec( const long* vals ); NcBool put_rec( const float* vals ); NcBool put_rec( const double* vals ); // Put a dimension slice worth of data in current dimension slice NcBool put_rec( NcDim* d, const ncbyte* vals ); NcBool put_rec( NcDim* d, const char* vals ); NcBool put_rec( NcDim* d, const short* vals ); NcBool put_rec( NcDim* d, const int* vals ); NcBool put_rec( NcDim* d, const long* vals ); NcBool put_rec( NcDim* d, const float* vals ); NcBool put_rec( NcDim* d, const double* vals ); // Put a record's worth of data in specified record NcBool put_rec( const ncbyte* vals, long rec ); NcBool put_rec( const char* vals, long rec ); NcBool put_rec( const short* vals, long rec ); NcBool put_rec( const int* vals, long rec ); NcBool put_rec( const long* vals, long rec ); NcBool put_rec( const float* vals, long rec ); NcBool put_rec( const double* vals, long rec ); // Put a dimension slice worth of data in specified dimension slice NcBool put_rec( NcDim* d, const ncbyte* vals, long slice ); NcBool put_rec( NcDim* d, const char* vals, long slice ); NcBool put_rec( NcDim* d, const short* vals, long slice ); NcBool put_rec( NcDim* d, const int* vals, long slice ); NcBool put_rec( NcDim* d, const long* vals, long slice ); NcBool put_rec( NcDim* d, const float* vals, long slice ); NcBool put_rec( NcDim* d, const double* vals, long slice ); // Get first record index corresponding to specified key value(s) long get_index( const ncbyte* vals ); long get_index( const char* vals ); long get_index( const short* vals ); long get_index( const int* vals ); long get_index( const long* vals ); long get_index( const float* vals ); long get_index( const double* vals ); // Get first index of specified dimension corresponding to key values long get_index( NcDim* d, const ncbyte* vals ); long get_index( NcDim* d, const char* vals ); long get_index( NcDim* d, const short* vals ); long get_index( NcDim* d, const int* vals ); long get_index( NcDim* d, const long* vals ); long get_index( NcDim* d, const float* vals ); long get_index( NcDim* d, const double* vals ); // Set current record void set_rec ( long rec ); // Set current dimension slice void set_rec ( NcDim* d, long slice ); int id( void ) const; // rarely needed, C interface id NcBool sync( void ); private: int dim_to_index(NcDim* rdim); int the_id; long* the_cur; char* the_name; long* cur_rec; // private constructors because only an NcFile creates these NcVar( void ); NcVar(NcFile*, int); int attnum( NcToken attname ) const; NcToken attname( int attnum ) const; void init_cur( void ); // to make variables, since constructor is private friend class NcFile; }; /* * ********************************************************************** * netCDF attributes. In addition to a name and a type, these are each * associated with a specific variable, or are global to the file. * ********************************************************************** */ class NcAtt : public NcTypedComponent { public: virtual ~NcAtt( void ); NcToken name( void ) const; NcType type( void ) const; NcBool is_valid( void ) const; long num_vals( void ) const; NcValues* values( void ) const; NcBool rename( NcToken newname ); NcBool remove( void ); private: const NcVar* the_variable; char* the_name; // protected constructors because only NcVars and NcFiles create // attributes NcAtt( NcFile*, const NcVar*, NcToken); NcAtt( NcFile*, NcToken); // global attribute // To make attributes, since constructor is private friend class NcFile; friend NcAtt* NcVar::get_att( NcToken ) const; }; /* * ********************************************************************** * To control error handling. Declaring an NcError object temporarily * changes the error-handling behavior until the object is destroyed, at * which time the previous error-handling behavior is restored. * ********************************************************************** */ class NcError { public: enum Behavior { silent_nonfatal = 0, silent_fatal = 1, verbose_nonfatal = 2, verbose_fatal = 3 }; // constructor saves previous error state, sets new state NcError( Behavior b = verbose_fatal ); // destructor restores previous error state virtual ~NcError( void ); int get_err( void ); // returns most recent error number const char* get_errmsg( void ) {return nc_strerror(get_err());} static int set_err( int err ); private: int the_old_state; int the_old_err; static int ncopts; static int ncerr; }; #endif /* NETCDF_HH */