As a response to Issue #15753. Not yet complete.
Some notes:
- All Rust translations assume the crate root (so the reference to
stdis freely available). The use of any other crates is noted. - Every string or vector argument is assumed to be a slice (
&stror&[T]). Otherwise you need to convertStringorVec<T>to a slice with.as_slice()method.
assert(cond):assert!(cond)macro. Note that it's always enabled; if you need to selectively disable the assertions, usedebug_assert!(cond)macro.static_assert(cond, err): In the limited fashion,#[static_assert] static ANY_NAME: bool = cond;will raise a compile-time error whencondevaluates tofalse. Since it is astaticitem,condis severely limited and cannot make any function call.
There are two major complex types: num::complex::Complex32 (for complex float) and num::complex::Complex64 (for complex double). If you have a custom floating point type, num::complex::Complex<T> is also usable. All of them needs extern crate num;. This section will refer to the Complex type which may be one of them.
I:Complex::new(0.0, 1.0). Well, see below.CMPLX*(x,y):Complex::new(x, y).
cacos*(z): No counterparts.casin*(z): No counterparts.catan*(z): No counterparts.ccos*(z): No counterparts.csin*(z): No counterparts.ctan*(z): No counterparts.
cacosh*(z): No counterparts.casinh*(z): No counterparts.catanh*(z): No counterparts.ccosh*(z): No counterparts.csinh*(z): No counterparts.ctanh*(z): No counterparts.
cexp*(z): No counterparts.clog*(z): No counterparts.
cabs*(z):z.norm().cpow*(x,y): No counterparts.csqrt*(z): No counterparts.
carg*(z):z.arg().cimag*(z):z.im.conj*(z):z.conj().cproj*(z): No counterparts.creal*(z):z.re.
The following functions are locale-dependent, so it is important to determine if you need a full Unicode version or just an 8-bit-safe version of these functions. The former assumes a normal char type, and the latter assumes the std::ascii::Ascii type which is a 7-bit subset of char. Fortunately for us, they mostly share the same set of methods available (with the std::char::UnicodeChar trait responsible for char).
The Unicode case mapping is a complicated matter and a care should be taken. Most notably, the Unicode version of tolower and toupper is incomplete in such that it can ever return one Unicode scalar value, while some scalar value can map to multiple scalar values.
isalnum(c):c.is_alphanumeric().isalpha(c):c.is_alphabetic().isblank(c):c.is_blank()forAscii. No counterpart inchar, but you can usec == ' ' || c == '\t'as a locale-independent workaround.iscntrl(c):c.is_control().isdigit(c):c.is_digit().isgraph(c):c.is_graph().islower(c):c.is_lowercase().isprint(c):c.is_print().ispunct(c):c.is_punctuation().isspace(c):c.is_whitespace()forchar. No counterpart inAscii, but you can usec == b' ' || c == b'\x0c' || c == b'\n' || c == b'\r' || c == b'\t' || c == b'\x0b'as a locale-independent workaround. (Yes, Rust does not support\for\v.)isupper(c):c.is_uppercase().isxdigit(c):c.is_hex()forAscii. Forchar,c.to_digit(16).is_some()is a slightly more flexible alternative.tolower(c):c.to_lowercase(). Note the warning above.toupper(c):c.to_uppercase(). Note the warning above.
Most use cases of errno is covered with the type-safe Result type. The following is only relevant when you are consulting the external library.
errno:std::os::errno(). Usestd::io::IoError::last_error()for converting it to a standard I/O error type.
I believe that Rust standard library does not have any counterparts to this header file.
In the list below, <type> means either f32 or f64 in Rust, and either FLT (for float) or DBL (for double) in C. There is no support for long double in Rust, so there is no counterpart for LDBL macros.
FLT_ROUNDS: No counterpart.FLT_EVAL_METHOD: No counterpart.FLT_RADIX:std::<type>::RADIX. Technicallyf32andf64may have a different radix.<type>_MANT_DIG:std::<type>::MANTISSA_DIGITS.<type>_DIGor<type>_DECIMAL_DIG:std::<type>::DIGITS. Note that there is no strong guarantee about whatDIGITSactually means yet.DECIMAL_DIG: If you really want this, usestd::f64::DIGITS.<type>_MIN_EXP:std::<type>::MIN_EXP.<type>_MIN_10_EXP:std::<type>::MIN_10_EXP.<type>_MAX_EXP:std::<type>::MAX_EXP.<type>_MAX_10_EXP:std::<type>::MAX_10_EXP.<type>_MAX:std::<type>::MAX_VALUE.<type>_EPSILON:std::<type>::EPSILON.<type>_MIN: No counterpart, as Rust does not guarantee thatMIN_POS_VALUEis a normalized value. Most uses of<type>_MINcan be substituted with<type>_TRUE_MINbelow though.<type>_TRUE_MIN:std::<type>::MIN_POS_VALUE.
imaxdiv_t: No counterpart. See below.
PRI*macros:format!and related macros eliminate the needs for such macros. Just use{},{:x}etc.SCN*macros: No counterparts.
imaxabs(j),imaxdiv(numer,denom),{str,wcs}to{i,u}max(nptr,endptr,base): No counterparts. Rust does not have anintmax_toruintmax_ttype (thoughi64andu64are likely the largest integer types).
Not applicable.
Unlike C, Rust's integral types have a defined size in most cases. For example, C's int and long int are the same type in many cases, but u64 is always distinct from u32. You need to determine exactly what Rust type is to be used; each integral type has its own module in std, so std::i64::MAX would be the maximum value of i64 for example. (See also <stdint.h>.)
The following list assumes that you are somehow forced to use types from the libc crate. You would need extern crate libc;. Most of them cannot be used in the static context, as it refers to the std::num::Bounded trait in run time.
CHAR_BIT: Not applicable. C'scharmaps tocharoru8/i8in Rust, and the number of bits inu8/i8is guaranteed to be 8.SCHAR_MIN:{ let min: libc::c_schar = std::num::Bounded::min_value(); min }.SCHAR_MAX:{ let max: libc::c_schar = std::num::Bounded::max_value(); max }.UCHAR_MAX:{ let max: libc::c_uchar = std::num::Bounded::max_value(); max }.CHAR_MIN:{ let min: libc::c_char = std::num::Bounded::min_value(); min }.CHAR_MAX:{ let max: libc::c_char = std::num::Bounded::max_value(); max }.MB_LEN_MAX:std::mem::size_of::<libc::wchar_t>().SHRT_MIN:{ let min: libc::c_short = std::num::Bounded::min_value(); min }.SHRT_MAX:{ let max: libc::c_short = std::num::Bounded::max_value(); max }.USHRT_MAX:{ let max: libc::c_ushort = std::num::Bounded::max_value(); max }.INT_MIN:{ let min: libc::c_int = std::num::Bounded::min_value(); min }.INT_MAX:{ let max: libc::c_int = std::num::Bounded::max_value(); max }.UINT_MAX:{ let max: libc::c_uint = std::num::Bounded::max_value(); max }.LONG_MIN:{ let min: libc::c_long = std::num::Bounded::min_value(); min }.LONG_MAX:{ let max: libc::c_long = std::num::Bounded::max_value(); max }.ULONG_MAX:{ let max: libc::c_ulong = std::num::Bounded::max_value(); max }.LLONG_MIN:{ let min: libc::c_llong = std::num::Bounded::min_value(); min }.LLONG_MAX:{ let max: libc::c_llong = std::num::Bounded::max_value(); max }.ULLONG_MAX:{ let max: libc::c_ullong = std::num::Bounded::max_value(); max }.
I believe that Rust standard library does not have any counterparts to this header file.
Most of the methods mentioned before are in the std::num::Signed, std::num::Float and std::num::FloatMath traits.
HUGE_VAL*: UseINFINITYinstead.INFINITY:std::<type>::INFINITY(where<type>is eitherf32orf64), orstd::num::Float::infinity().NAN:std::<type>::NAN, orstd::num::Float::nan().FP_INFINITE,FP_NAN,FP_NORMAL,FP_SUBNORMAL,FP_ZERO:std::num::{FPInfinite, FPNaN, FPNormal, FPSubnormal, FPZero}respectively. They are of the typestd::num::FPCategory.FP_FAST_FMA*: No counterparts.FP_ILOGB0,FP_ILOGBNAN: No counterparts.MATH_ERRNO,MATH_ERREXCEPT,math_errhandling: No counterparts.
fpclassify(x):x.classify().isfinite(x):x.is_finite().isinf(x):x.is_infinite().isnan(x):x.is_nan().isnormal(x):x.is_normal().signbit(x):x.integer_decode().val2().x.signum()is almost identical, but it returns a floating point value and may return NaN for NaN arguments.
acos*(x):x.acos().asin*(x):x.asin().atan*(x):x.atan().atan2*(y,x):y.atan2(x).cos*(x):x.cos().sin*(x):x.sin().tan*(x):x.tan().
acosh*(x):x.acosh().asinh*(x):x.asinh().atanh*(x):x.atanh().cosh*(x):x.cosh().sinh*(x):x.sinh().tanh*(x):x.tanh().
exp*(x):x.exp().exp2*(x):x.exp2().expm1*(x):x.exp_m1().frexp*(value,exp):value.frexp(). The original return value andexpare returned as a tuple.ilogb*(x): No counterparts.ldexp*(x,exp):x.ldexp(exp).log*(x):x.ln().log10*(x):x.log10().log1p*(x):x.ln_1p().log2*(x):x.log2().logb*(x): No counterparts.modf*(value,iptr):value.fract()for the return value,value.trunc()foriptr.scalbn*(x,n),scalbln*(x,n): No counterparts.{ let (frac,exp) = x.frexp(); frac.ldexp(exp + n) }can be used as an workaround.
cbrt*(x):x.cbrt().fabs*(x):x.abs()orstd::num::abs(x).hypot*(x,y):x.hypot(y).pow*(x,y):x.powf(y)orstd::num::pow(x,y).sqrt*(x):x.sqrt().
erf*(x): No counterparts.erfc*(x): No counterparts.lgamma*(x): No counterparts.tgamma*(x): No counterparts.
ceil*(x):x.ceil().floor*(x):x.floor().nearbyint*(x): No counterparts.rint*(x): No counterparts.lrint*(x),llrint*(x): No counterparts.round*(x):x.round().lround*(x),llround*(x): No counterparts.x.round().to_<type>()may be used as an workaround.trunc*(x):x.trunc().
fmod*(x,y):x % y.remainder*(x,y): No counterparts.remquo*(x,y): No counterparts.
copysign*(x,y): No counterparts.nan*(tagp): No counterparts. There is no direct way to construct a NaN with an explicit payload.nextafter*(x,y):x.next_after(y).nexttoward*(x,y): No counterparts.
fdim*(x,y):x.abs_sub(y)orstd::num::abs_sub(x, y).fmax*(x,y):x.max(y). Note that floating point types do not implement theOrdtrait due to the presence of NaNs, sostd::cmp::max(x,y)cannot be used.fmin*(x,y):x.min(y). The same note applies.
fma*(x,y,z):x.mul_add(y, z).
isgreater(x,y): No counterpart.x > ywould work without the guarantee about floating point exceptions.isgreaterequal(x,y): No counterpart.x >= ywould work without the guarantee.isless(x,y): No counterpart.x < ywould work without the guarantee.islessequal(x,y): No counterpart.x <= ywould work without the guarantee.islessgreater(x,y): No counterpart.x < y || x > ywould work without the guarantee.isunordered(x,y): No counterpart.
I believe that Rust standard library does not have any counterparts to this header file.
sig_atomic_t: Thestd::sync::atomicsmodule provides a number of atomic primitive types.SIG_DFL,SIG_ERR,SIG_IGN: Not applicable.SIGABRT,SIGFPE,SIGILL,SIGINT,SIGSEGV,SIGTERM: Thelibccrate hasstatics for them, which can be used instd::io::process::Process::signalfor example. For the use instd::io::signal::Listener(see below),STDINTalso hasstd::io::signal::Interrupt.
signal(sig,func): No direct counterpart.std::io::signal::Listenerprovides a safe interface around it, but it does not execute the interrupts asynchronously.
raise(sig): No counterpart.
alignas(align): No counterpart. Structures can have the#[packed]attribute which is effectively equivalent toalignas(1)in every field though.alignof(type):std::mem::align_of::<type>().
No counterparts. Rust supports the call to the external function with variadic arguments, but there is no support for manipulating va_list.
Rust has the built-in bool type and true and false values.
ptrdiff_t:libc::ptrdiff_t.size_t:libc::size_t. For the pure Rust,uintis guaranteed to be able to store any valid array indices.max_align_t: No counterpart.wchar_t:libc::wchar_t. For the pure Rust, usechar.NULL:std::ptr::null()orstd::ptr::mut_null(), depending on the underlying raw pointer type (*const Tor*mut T). For the pure Rust, use an explicitOptiontype andNone.offsetof(type,member): No counterpart.
In the following list, <N> can be either 8, 16, 32 or 64. For any other value there is no counterpart. Also note that int<N>_t, uint<N>_t, intptr_t and uintptr_t are also available in the libc crate; they need extern crate libc;.
int<N>_t:i<N>.uint<N>_t:u<N>.int_least<N>_t: No direct counterparts.uint_least<N>_t: No direct counterparts.int_fast<N>_t: No counterparts.uint_fast<N>_t: No counterparts.intptr_t:int.uintptr_t:uint.intmax_t: No counterpart.uintmax_t: No counterpart.
INT<N>_MIN:std::i<N>::MIN.INT<N>_MAX:std::i<N>::MAX.UINT<N>_MAX:std::u<N>::MAX.INT_LEAST<N>_MIN: No counterparts.INT_LEAST<N>_MAX: No counterparts.UINT_LEAST<N>_MAX: No counterparts.INT_FAST<N>_MIN: No counterparts.INT_FAST<N>_MAX: No counterparts.UINT_FAST<N>_MAX: No counterparts.INTPTR_MIN:std::int::MIN.INTPTR_MAX:std::int::MAX.UINTPTR_MAX:std::uint::MAX.INTMAX_MIN: No counterpart.INTMAX_MAX: No counterpart.UINTMAX_MAX: No counterpart.
PTRDIFF_MIN: No counterpart.PTRDIFF_MAX: No counterpart.SIG_ATOMIC_MIN: No counterpart.SIG_ATOMIC_MAX: No counterpart.SIZE_MAX: No counterpart. You may use{ let max: libc::size_t = std::num::Bounded::max_value(); max }as an workaround.WCHAR_MIN: No counterpart. You may use{ let min: libc::wchar_t = std::num::Bounded::min_value(); min }as an workaround.WCHAR_MAX: No counterpart. You may use{ let max: libc::wchar_t = std::num::Bounded::max_value(); max }as an workaround.WINT_MIN: No counterpart.WINT_MAX: No counterpart.
INT<N>_C(value):i<N>suffix to the integer literal, e.g.42i8.UINT<N>_C(value):u<N>suffix to the integer literal, e.g.42u8.INTMAX_C(value): No counterpart.UINTMAX_C(value): No counterpart.
Most I/O functions and methods return a Result with std::io::IoError (i.e. std::io::IoResult<T>). One should check if the operation resulted in an error; use the try! macro to propagate it to the caller (in the function returning another IoResult), or .unwrap() method to terminate the current task on an error.
FILE: Depending on the capability,std::io::Reader(read-only),std::io::Buffer(read-only buffered, some methods likeread_linedepend on it),std::io::Writer(write-only) orstd::io::Stream(read-write). They are also commonly used as their trait object form, such as&mut Reader.fpos_t: No counterpart._IOFBF,_IOLBF,_IONBF: Not applicable. Seesetvbufbelow.BUFSIZ: Not applicable. Seesetvbufbelow.EOF: The end of file is indicated with a dedicatedstd::io::IoErrorvalue with its kind beingstd::io::EndOfFile.FOPEN_MAX: No counterpart.FILENAME_MAX: No counterpart.L_tmpnam: No counterpart.SEEK_CUR,SEEK_END,SEEK_SET:std::io::SeekCur,std::io::SeekEnd,std::io::SeekSetrespectively. They are of the typestd::io::SeekStyle.TMP_MAX: No counterpart.stderr,stdin,stdout:std::io::stderr(),std::io::stdin(),std::io::stdout()respectively. Note that they are not global streams and there may be multiple instances of them across multiple tasks. For this reason, you would want to use a normalprint!orprintln!macro instead ofstdout. Also note that they are already buffered, usestd::io::stderr_raw()and so on to get the raw stream (see alsosetvbufbelow).
remove(filename):std::io::fs::unlink(filename). Iffilenameis not aPath, use&Path::new(filename)instead offilename.rename(old,new):std::io::fs::rename(old, new). The same note asremoveapplies.tmpfile(): No counterpart.std::io::TempDir(which creates a temporary directory) can be used to achieve the similar thing.tmpnam(s): No counterpart. Seetmpfileabove.
fclose(stream): Automatically closed on the end of scope. Usedrop(stream)to explicitly deallocate the stream.fflush(stream):stream.flush().fopen(filename,mode):std::io::File::open_mode(filename, mode, access)with an appropriatemodeandaccessvalue. The common values areOpen/Readfor"r"andTruncate/Writefor"w";File::open(filename)andFile::create(filename)are provided as shortcuts. Iffilenameis not aPath, use&Path::new(filename)instead offilename.freopen(filename,mode,stream): No counterpart.setbuf(stream,buf): No direct counterpart whenbufis notNULL. Seesetvbufotherwise.setvbuf(stream,buf,mode,size): No direct counterpart whenbufis notNULL. While Rust's stream does not have a buffer by default, the following types wrap the raw stream to provide buffering semantics.std::io::LineBufferedWriter::new(stream)is similar to howstreamwould behave aftersetvbuf(stream,NULL,_IOLBF,BUFSIZ).std::io::BufferedReader::new(stream)is similar to howstreamwould behave aftersetvbuf(stream,NULL,_IOFBF,BUFSIZ).std::io::BufferedReader::with_capacity(size, stream)is similar to howstreamwould behave aftersetvbuf(stream,NULL,_IOFBF,size).- Similarly, there are
std::io::BufferedWriterandstd::io::BufferedStreamforWriterandStream.
fprintf(stream,format,...):write!(stream, format, ...).streamshould be of the type&mut Writer, andformatshould be a compile-time constant string (as it gets processed by the compiler). Rust's format syntax is radically different from C's, see thestd::fmtdocumentation for details.fscanf(stream,format,...): No counterpart. But you can directly read a line (stream.read_line()) or a whole file (stream.read_to_string()) to parse it by yourself; once the input is available, theregexcrate andfrom_strcan do many of things possible withsscanf.printf(format,...):print!(format, ...), orprintln!(format, ...)ifformatends with\n. The same note asfprintfapplies.scanf(format,...): No counterpart. Seefscanf.snprintf(s,n,format,...): You normally don't need this, asnis mostly to stop the buffer overflow. Seesprintf.sprintf(s,format,...):format!(format, ...). The same note asfprintfapplies. This returnsStringand very safe from the buffer overflow unlike the original C function.sscanf(s,format,...): No counterpart. Seefscanf.vfprintf(stream,format,arg): No direct counterpart, asva_listis not supported. If you want to make your own formatting function, you'd better writing a macro overformat_args!(|args| std::fmt::write(stream, args), ...); see thestd::fmtdocumentation for details.vfscanf(stream,format,arg): No counterpart. Seefscanf.vprintf(format,arg): No direct counterpart, but you can write a macro overformat_args!(std::io::stdio::print_args, ...). Seevfprintf.vscanf(format,arg): No counterpart. Seefscanf.vsnprintf(s,n,format,arg): You normally don't need this, asnis mostly to stop the buffer overflow. Seesprintf.vsprintf(s,format,arg): No direct counterpart, but you can write a macro overformat_args!(std::fmt::format, ...). Seevfprintf.vsscanf(s,format,arg): No counterpart. Seefscanf.
fgetc(stream):stream.read_char()to get achar,stream.read_byte()to get au8. The former only works forBuffer, so the raw stream has to be converted to the buffered reader (seesetvbufabove).fgets(s,n,stream):stream.read_at_least(1, n, &mut s)wheresis aVec<u8>. There are a family of related methods inReader.fputc(c,stream):stream.write_char(c)to write achar(as a UTF-8 string),stream.write_u8(c)to write au8.fputs(s,stream):stream.write_str(s)to write a Unicode string,stream.write(s)to write a byte buffer.getc(stream): Seefgetc.getchar(): Usefgetccounterparts with thestd::io::stdin()stream. You may want to keep the resulting stream to avoid redundant allocations.putc(c,stream): Seefputc.putchar(c):print!("{}", c)to write achar(as a UTF-8 string). It is not desirable to write a raw byte to the standard output, but you can usefputccounterparts with thestd::io::stdout()stream.puts(s):print!("{}", s)orprint!("...")(for the fixeds) to write a Unicode string. Again, you can usefputscounterparts with thestd::io::stdout()stream to write an arbitrary byte sequence.ungetc(c,stream): No direct counterpart. Thestd::io::Bufferdoes not allow to rollback a read, but you can peek the buffer to achieve the similar behavior. Thereforeint c = fgetc(); ungetc(c,stream); cwould translate tostream.fill_buf().map(|buf| buf[0]).
fread(ptr,size,nmemb,stream):stream.push_at_least(1, size * nmemb, &mut ptr).map(|read_byte| read_byte / size). There is no direct way to force reading a multiple ofsizebytes however.fwrite(ptr,size,nmemb,stream):stream.write(ptr.slice_from(size * nmemb)). There is no direct way to get the number of bytes orsize-byte elements actually written however.
fgetpos(stream,pos): No counterpart, as Rust's stream does not have the parse state. Seeftellbelow.fseek(stream,offset,whence):stream.seek(offset, whence)wherewhenceis an appropriatestd::io::SeekStylevalue. This is defined in thestd::io::Seektrait, which many streams includingFileimplement.fsetpos(stream,pos): No counterpart, as Rust's stream does not have the parse state. Seefseekabove.ftell(stream):stream.tell(). This is defined in thestd::io::Seektrait, which many streams includingFileimplement.rewind(stream):stream.seek(0, std::io::SeekSet).
clearerr(stream): Not applicable. Rust's stream does not have an associated error state, and every operation to the stream may return anIoErrorwhich the caller has to somehow check or process.feof(stream): Not applicable. SeeclearerrandEOF.ferror(stream): Not applicable. Seeclearerr.perror(s):write!(&mut std::io::stderr(), "{}: {}", s, std::io::IoError::last_error()). TheIoErroris more commonly retrieved from the return value of I/O operations though.
div_t,ldiv_t,lldiv_t: Not applicable.std::num::div_rem(a counterpart to C'sdivand others) will simply return a tuple.EXIT_FAILURE,EXIT_SUCCESS: Not applicable. Rust does not have an explicitexitfunction. Usestd::os::set_exit_status()with a non-zero argument to indicate the error.RAND_MAX: Not applicable. Rust'sstd::rand::Rngtrait provides a number of convenience methods to get a random number in the exact domain, so it would be rarely needed. Note thatRngimplementations themselves are expected to provide the fullu32oru64random numbers.MB_CUR_MAX: No counterpart.
atof(nptr): Assuming thatTis a floating point type,from_str::<T>(nptr).unwrap_or(0.0)wherenptris a string slice. You may want to handle errors more properly.atoi(nptr),atol(nptr),atoll(nptr): Assuming thatTis an integer type (signed or not),from_str::<T>(nptr).unwrap_or(0)wherenptris a string slice. Again, you may want to handle errors more properly.strtod(nptr,endptr),strtof(nptr,endptr),strtold(nptr,endptr): No counterparts.from_strcan only parse a string as a whole.strtol(nptr,endptr),strtoll(nptr,endptr),strtoul(nptr,endptr),strtoull(nptr,endptr): No counterparts.from_strcan only parse a string as a whole. You may parse the string yourself (e.g.nptr.slice_to(nptr.find(|c| !c.is_digit()).unwrap_or(nptr.len()))) and feed it tofrom_strthough.
rand():std::rand::random::<int>(). In fact, you can generate other types thanintas long as it implementsstd::rand::Randtrait. Also, if you want to generate an integer betweenlowtohigh(exclusive), usestd::rand::task_rng().gen_range(low, high).srand(seed): You normally don't need this, as the default task-local generator is automatically seeded. If you need the repeatable result, pick an exact RNG algorithm fromstd::randand usestd::rand::SeedableRng::from_seed(seed)to make a generator with given seed. Don't forget that you actually need to use methods from that generator.
You normally don't need any of these. Always use automatically managed types like Vec<T>, String or Box<T> unless you know what you do.
aligned_malloc(alignment,size):std::rt::heap::allocate(size, alignment).calloc(nmemb,size):{ let ptr = std::rt::heap::allocate(nmemb * size, alignment); std::ptr::zero_memory(ptr, nmemb * size); ptr }with an appropriatealignment.free(ptr): Safe types get automatically deallocated at the end of scope. If you want to be explicit, though, you can usedrop(ptr). For the raw memory allocated withstd::rt::heap::allocate, usestd::rt::heap::deallocate(ptr, size, alignment); you need to keepsizeandalignmentknown.malloc(size):std::rt::heap::allocate(size, alignment)with an appropriatealignment.realloc(ptr,size):std::rt::heap::reallocate(ptr, size, alignment, old_size); again, you need to keepold_sizeandalignmentknown.std::rt::heap::reallocate_inplaceis similar but tries to keep the original pointer and returns false if impossible.
abort(): Usefail!()to terminate the current task. You can also usecore::intrinsics::abort()withextern crate core;, but it should be avoided if possible.atexit(func): In the limited fashion,std::rt::at_exit(func). Prefer the per-task cleanup provided bystd::task::TaskBuilderinstead.at_quick_exit(func): No counterpart.exit(status): No direct counterpart.std::os::set_exit_status(status)can be used to set the exit status when the program terminates otherwise normally (and does not terminate immediately). You can also wrap the entire process into a separate task and intercept any task failures to set the correct exit status in the main task._Exit(status): No counterpart.getenv(name):std::os::getenv(name). Note that this assumes a UTF-8 string, you should usestd::os::getenv_as_bytes(name)to get the original byte vector.quick_exit(status): No counterpart.system(string): Givenstringis"program arg1 ... argN", usestd::io::Command::new("program").arg("arg1")...arg("argN").spawn(). (If the string is dynamic, usestring.words().to_vec()to get a vector of arguments.) This returns anstd::io::process::Processvalue used to control the child process.
bsearch(key,base,nmemb,size,compar):base.slice_to(nmemb).bsearch(|v| 0.cmp(&compar(&key, v))). In the other words, Rust'sbsearchmethod expects a function which returns theOrderingofvagainst (the implicit)key(the opposite of what C'sbsearchexpects). Rust's closure would simplify the actual code a lot; for example, in order to find42fromVec<uint>, usevec.bsearch(|v| v.cmp(&42u)).qsort(base,nmemb,size,compar):base.mut_slice_to(nmemb).sort_by(|a,b| compar(a, b).cmp(&0)), orbase.mut_slice_to(nmemb).sort()to use the defaultOrdtrait. Note that some types comparable in C are not comparable in Rust, e.g.f32orf64. Again, the actual code is much simpler; for example, in order to sort by a particular field, usevec.sort_by(|a, b| a.foo.cmp(&b.foo)).
abs(j),labs(j),llabs(j):j.abs().div(numer,denom),ldiv(numer,denom),lldiv(numer,denom):std::num::div_rem(numer, denom).
mblen(s,n):mbtowc(pwc,s,n)wctomb(s,wc)
mbstowcs(pwcs,s,n)wcstombs(s,pwcs,n)
C's noreturn attribute is akin to Rust's -> ! return type.
Depending on the intention, a char pointer maps to either a Unicode string (String, &str) or a byte vector (Vec<u8>, &[u8]). It may also mean the unsafe generic pointer. The following list gives counterparts for all three cases.
Many functions with the explicit size parameter n are redundant in Rust, primarily because n is used only to avoid accidental buffer overflows. Both String and Vec<u8> automatically grow whenever required. Use .slice_to(n) method to explicitly use the first n bytes of the string or vector. Note that slice_to can still fail for a Unicode string when it would cut the multibyte UTF-8 sequence in the middle.
memcpy(s1,s2,n):- Unicode strings cannot be directly manipulated.
- For byte vectors,
std::slice::bytes::copy_memory(s1.mut_slice_to(n), s2.slice_to(n)). - For raw pointers,
std::ptr::copy_nonoverlapping_memory(s1, s2, n).
memmove(s1,s2,n):- Unicode strings cannot be directly manipulated.
- For byte vectors, same as
memcpy(the compiler ensures thats1ands2does not overlap). - For raw pointers,
std::ptr::copy_memory(s1, s2, n).
strcpy(s1,s2):- For Unicode strings,
s1 = s2.as_slice()ors1 = s2.to_string()depending on the type ofs1. - For byte vectors,
s1 = s2.as_slice()ors1 = s2.to_vec()depending on the type ofs1. - For raw pointers, there is no direct counterpart. Use an explicit loop.
- For Unicode strings,
strncpy(s1,s2,n):- For Unicode strings,
s1 = s2.slice_to(n)ors1 = s2.slice_to(n).to_string()depending on the type ofs1. As noted above, you wouldn't normally use this; seestrcpyfor more natural usages. - For byte vectors,
s1 = s2.slice_to(n)ors1 = s2.slice_to(n).to_vec()depending on the type ofs1. - For raw pointers, there is no direct counterpart. Use an explicit loop.
- For Unicode strings,
strcat(s1,s2):- For Unicode strings and byte vectors,
s1.push_all(s2). Ifs2is an ownedStringorVec<u8>and you wouldn't uses2later,s1.push_all_move(s2)can also be used. - For raw pointers, there is no direct counterpart. Use an explicit loop.
- For Unicode strings and byte vectors,
strncat(s1,s2,n):- For Unicode strings and byte vectors,
s1.push_all(s2.slice_to(n)). As noted above, you wouldn't normally use this for Unicode strings; seestrcatfor more natural usages. - For raw pointers, there is no direct counterpart. Use an explicit loop.
- For Unicode strings and byte vectors,
memcmp(s1,s2,n):- For Unicode strings and byte vectors,
s1.slice_to(n).cmp(&s2.slice_to(n)). Ifnequates tos2.len()(i.e. iss2a prefix ofs1), there is a shorters1.starts_with(s2). As noted above, you wouldn't normally use this for Unicode strings; seestrcmpfor more natural usages. - For raw pointers, convert
s1ands2withstd::slice::raw::buf_as_sliceand treat them as like byte vectors.
- For Unicode strings and byte vectors,
strcmp(s1,s2):- For Unicode strings and byte vectors,
s1.cmp(&s2). (Simple, eh?) - For raw pointers,
CString::new(s1, false).cmp(&CString::new(s2, false))whereCStringisstd::c_str::CString. In fact, you can wrap a raw buffer withCStringto use it like a normal byte vector.
- For Unicode strings and byte vectors,
strcoll(s1,s2): No counterpart.strncmp(s1,s2,n): Same asmemcmp, except that one should be careful fornnot to exceeds1.len()ors2.len().strxfrm(s1,s2,n): No counterpart.
memchr(s,c,n):- For Unicode strings,
s.slice_to(n).find(c). As noted above, you wouldn't normally use this for Unicode strings; seestrchrfor more natural usages. - For byte vectors,
s.slice_to(n).iter().position(|&v| v == c). - For raw pointers, convert
swithstd::slice::raw::buf_as_sliceand treat it as like a byte vector.
- For Unicode strings,
strchr(s,c):- For Unicode strings,
s.find(c). - For byte vectors,
s.slice_to(n).iter().position(|&v| v == c). - For raw pointers, convert
swithstd::c_str::CStringand treat it as like a byte vector. (Seestrcmpfor an example.)
- For Unicode strings,
strcspn(s1,s2):- For Unicode strings,
s1.find(|c| !s2.contains(c)).unwrap_or(s1.len()). That is, try to find the first character not ins2, and if there is none, use the length ofs1instead. Ifs2is fixed, using a slice of characters (e.g.&['a', 'b', 'c']) instead of|c| !s2.contains(c)may be much faster in the current implementation. - For byte vectors,
s1.iter().position(|&c| !s2.contains(&c)).unwrap_or(s1.len()). - For raw pointers, convert
s1ands2withstd::c_str::CStringand treat them as like byte vectors. (Seestrcmpfor an example.)
- For Unicode strings,
strpbrk(s1,s2):- For Unicode strings,
s1.find(|c| s2.contains(c)). The same note asstrcspnapplies. - For byte vectors,
s1.iter().position(|&c| s2.contains(&c)). - For raw pointers, convert
s1ands2withstd::c_str::CStringand treat them as like byte vectors. (Seestrcmpfor an example.)
- For Unicode strings,
strrchr(s,c):- For Unicode strings,
s.rfind(c). - For byte vectors,
s.slice_to(n).iter().rposition(|&v| v == c). - For raw pointers, convert
swithstd::c_str::CStringand treat it as like a byte vector. (Seestrcmpfor an example.)
- For Unicode strings,
strspn(s1,s2):- For Unicode strings,
s1.find(|c| s2.contains(c)).unwrap_or(s1.len()). The same note asstrcspnapplies. - For byte vectors,
s1.iter().position(|&c| s2.contains(&c)).unwrap_or(s1.len()). - For raw pointers, convert
s1ands2withstd::c_str::CStringand treat them as like byte vectors. (Seestrcmpfor an example.)
- For Unicode strings,
strstr(s1,s2):- For Unicode strings,
s1.find_str(s2). - There are no counterparts for other cases.
- For Unicode strings,
strtok(s1,s2):- For Unicode strings with the same
s2at each call,for part in s1.split(|c| s2.contains(c)) { ... }will give each slice topart. The same note asstrcspnapplies. - For byte vectors with the same
s2at each call,for part in s1.split(|&c| s2.contains(&c)) { ... }will give each slice topart. - For Unicode strings or byte vectors with the different
s2at each call, you need to iteratively find the first separator in the current slice (seestrchr), use a slice up to that position, set the current slice to a portion after the separator and continue. - For raw pointers, convert
s1ands2withstd::c_str::CStringand treat them as like byte vectors. (Seestrcmpfor an example.)
- For Unicode strings with the same
memset(s,c,n):- Unicode strings cannot be directly manipulated. If you need a string with the same character repeated
ntimes, usec.to_string().repeat(n). - For byte vectors,
s.mut_slice_to(n).set_memory(c). It needsuse std::slice::bytes::MutableByteVector;. - For raw pointers,
std::ptr::set_memory(s, c, n).
- Unicode strings cannot be directly manipulated. If you need a string with the same character repeated
strerror(errnum):std::os::error_string(errnum).strlen(s):- For Unicode strings and byte vectors,
s.len(). - For raw pointers,
std::c_str::CString::new(s, false).len().
- For Unicode strings and byte vectors,
Rust's mathematical functions are based on a number of traits, and consequently, automatically type-general. See <math.h>.
thread_local:#[thread_local]attribute. Normally you don't need this (unless you need to link with the external library using it); seetss_t.ONCE_FLAG_INIT:std::sync::ONCE_INIT.TSS_DTOR_ITERATIONScnd_tthrd_t: There is no explicit handle to the running task. The task body normally takes channels and/or atomically managed types from the outer environment to communicate with each other. The Rust runtime (std::rt) contains an interface to the native thread, but its direct use is not recommended.tss_t:std::local_data::Key. Do not use this as is;local_data_key!(name: type)defines a globalnameused to access the task-local value of typetype.mtx_ttss_dtor_t: No direct counterpart; seetss_create.thrd_start_t: No direct counterpart, but any function which spawns a task uses a sendable procedure type (proc(): Send) as a body.once_flag:std::sync::Once.mtx_plainmtx_recursivemtx_timedthrd_timedout,thrd_success,thrd_busy,thrd_error,thrd_nomem: Not applicable (the error during spawning a task is a fatal failure).
call_once(flag,func):flag.doit(func).funccan be any closure, i.e. it can refer to the calling environment.
cnd_broadcast(cond)cnd_destroy(cond)cnd_init(cond)cnd_signal(cond)cnd_timedwait(cond,mtx,ts)cnd_wait(cond,mtx)
mtx_destroy(mtx)mtx_init(mtx,type)mtx_lock(mtx)mtx_timedlock(mtx,ts)mtx_trylock(mtx)mtx_unlock(mtx)
C's thread maps to Rust's task, which may be a native thread (default) or a coroutine behind the scene. The task completely encapsulates its environment and a task cannot abruptly terminate or control other tasks; instead, a number of communication and synchronization types are used to manage tasks. Consequently many of the following functions are not applicable in Rust, though this list tries to provide some alternatives to achieve similar effects.
thrd_create(thr,func,arg):std::task::spawn(func)(but see alsothrd_join).thris not applicable (seethrd_tabove), andargshould be moved from the outer environment tofuncprocedure. Note that there is no strong guarantee on the beginning of new task; usestd::sync::Barrierto ensure that.thrd_current(): Not applicable; seethrd_tabove.thrd_detach(thr): Not applicable; seethrd_joinbelow.thrd_equal(thr0,thr1): Not applicable; seethrd_tabove.thrd_exit(res): The task body can return or fail (viafail!and many other means) to terminate the current task. Any resource allocated over the course is safely destroyed even on the failure. Seethrd_joinfor how to return an arbitraryres(though other communication primitives would equally work).thrd_join(thr,res): Not applicable. If you need to block the current task until another task finishes, spawn a new task viastd::task::try(func). Its return value contains a return value offuncon success, so it can be used as a substitute ofthrd_exitas well.thrd_sleep(duration,remaining):std::io::timer::sleep(duration)withdurationin milliseconds. Rust task cannot be interrupted otherwise stated, soremainingis not applicable.thrd_yield():std::task::deschedule().
tss_create(key,dtor): This is implicit (the task-local storage is initialized withNone). For a non-nulldtor, use a custom type implementingDroptrait; the runtime is responsible for destroying any initialized task-local values on the task exit.tss_delete(key):key.replace(None). Note thatkeystill remains usable; this would only remove the value out of the storage.tss_get(key):key.get(). It may returnNonewhen the storage is empty.tss_set(key,val):key.replace(Some(val)). It would move the previous value out of the storage.
All of the following types and functions needs extern crate time; in Rust.
CLOCKS_PER_SEC: No counterpart. Two counterparts toclockuse the fixed unit (seconds and nanoseconds respectively) though.TIME_UTC: No counterpart; seetimespec_get.clock_t: No counterpart; seeclock.time_t: No counterpart, butstruct timespec(and itstv_secfield) can be used in place oftime_tstruct timespec:time::Timespec.tv_secandtv_nsecfields are renamed tosecandnsecrespectively.struct tm:time::Tm. Field names remain unchanged.
clock():time::precise_time_s()(in seconds) ortime::precise_time_ns()(in nanoseconds).difftime(time1,time0): No counterpart, but(time1.sec - time0.sec) as f64 + (time1.nsec - time0.nsec) as f64 / 1e9will return the number of seconds between twotime::Timespecs.mktime(timeptr):timeptr.to_timespec().sec. Note that this does not handle the error (in which casemktimewould return-1) correctly.time(timer):time::get_time().sec.timeris redundant.timespec_get(ts,base):time::get_time()whenbaseequals toTIME_UTC. No counterpart otherwise.
asctime(timeptr):timeptr.asctime(). This is safe across multiple calls to it.ctime(timer):time::at(timer).asctime()wheretimeris atime::Timespec.gmtime(timer):time::at_utc(timer)wheretimeris atime::Timespec.localtime(timer):time::at(timer)wheretimeris atime::Timespec.strftime(s,maxsize,format,timeptr):timeptr.strftime(format)with the sameformatas C. It returns a fully allocatedStringand thusmaxtimeis redundant.