As a response to Issue #15753. Not yet complete.
Some notes:
- All Rust translations assume the crate root (so the reference to
std
is freely available). The use of any other crates is noted. - Every string or vector argument is assumed to be a slice (
&str
or&[T]
). Otherwise you need to convertString
orVec<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 whencond
evaluates tofalse
. Since it is astatic
item,cond
is 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\f
or\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
. Technicallyf32
andf64
may have a different radix.<type>_MANT_DIG
:std::<type>::MANTISSA_DIGITS
.<type>_DIG
or<type>_DECIMAL_DIG
:std::<type>::DIGITS
. Note that there is no strong guarantee about whatDIGITS
actually 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_VALUE
is a normalized value. Most uses of<type>_MIN
can be substituted with<type>_TRUE_MIN
below 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_t
oruintmax_t
type (thoughi64
andu64
are 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'schar
maps tochar
oru8
/i8
in Rust, and the number of bits inu8
/i8
is 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*
: UseINFINITY
instead.INFINITY
:std::<type>::INFINITY
(where<type>
is eitherf32
orf64
), 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 andexp
are 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 theOrd
trait 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 > y
would work without the guarantee about floating point exceptions.isgreaterequal(x,y)
: No counterpart.x >= y
would work without the guarantee.isless(x,y)
: No counterpart.x < y
would work without the guarantee.islessequal(x,y)
: No counterpart.x <= y
would work without the guarantee.islessgreater(x,y)
: No counterpart.x < y || x > y
would 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::atomics
module provides a number of atomic primitive types.SIG_DFL
,SIG_ERR
,SIG_IGN
: Not applicable.SIGABRT
,SIGFPE
,SIGILL
,SIGINT
,SIGSEGV
,SIGTERM
: Thelibc
crate hasstatic
s for them, which can be used instd::io::process::Process::signal
for example. For the use instd::io::signal::Listener
(see below),STDINT
also hasstd::io::signal::Interrupt
.
signal(sig,func)
: No direct counterpart.std::io::signal::Listener
provides 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,uint
is 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 T
or*mut T
). For the pure Rust, use an explicitOption
type 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_line
depend 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. Seesetvbuf
below.BUFSIZ
: Not applicable. Seesetvbuf
below.EOF
: The end of file is indicated with a dedicatedstd::io::IoError
value 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::SeekSet
respectively. 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 alsosetvbuf
below).
remove(filename)
:std::io::fs::unlink(filename)
. Iffilename
is not aPath
, use&Path::new(filename)
instead offilename
.rename(old,new)
:std::io::fs::rename(old, new)
. The same note asremove
applies.tmpfile()
: No counterpart.std::io::TempDir
(which creates a temporary directory) can be used to achieve the similar thing.tmpnam(s)
: No counterpart. Seetmpfile
above.
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 appropriatemode
andaccess
value. The common values areOpen
/Read
for"r"
andTruncate
/Write
for"w"
;File::open(filename)
andFile::create(filename)
are provided as shortcuts. Iffilename
is not aPath
, use&Path::new(filename)
instead offilename
.freopen(filename,mode,stream)
: No counterpart.setbuf(stream,buf)
: No direct counterpart whenbuf
is notNULL
. Seesetvbuf
otherwise.setvbuf(stream,buf,mode,size)
: No direct counterpart whenbuf
is 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 howstream
would behave aftersetvbuf(stream,NULL,_IOLBF,BUFSIZ)
.std::io::BufferedReader::new(stream)
is similar to howstream
would behave aftersetvbuf(stream,NULL,_IOFBF,BUFSIZ)
.std::io::BufferedReader::with_capacity(size, stream)
is similar to howstream
would behave aftersetvbuf(stream,NULL,_IOFBF,size)
.- Similarly, there are
std::io::BufferedWriter
andstd::io::BufferedStream
forWriter
andStream
.
fprintf(stream,format,...)
:write!(stream, format, ...)
.stream
should be of the type&mut Writer
, andformat
should 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::fmt
documentation 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, theregex
crate andfrom_str
can do many of things possible withsscanf
.printf(format,...)
:print!(format, ...)
, orprintln!(format, ...)
ifformat
ends with\n
. The same note asfprintf
applies.scanf(format,...)
: No counterpart. Seefscanf
.snprintf(s,n,format,...)
: You normally don't need this, asn
is mostly to stop the buffer overflow. Seesprintf
.sprintf(s,format,...)
:format!(format, ...)
. The same note asfprintf
applies. This returnsString
and 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_list
is 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::fmt
documentation 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, asn
is 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 (seesetvbuf
above).fgets(s,n,stream)
:stream.read_at_least(1, n, &mut s)
wheres
is 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()
: Usefgetc
counterparts 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 usefputc
counterparts with thestd::io::stdout()
stream.puts(s)
:print!("{}", s)
orprint!("...")
(for the fixeds
) to write a Unicode string. Again, you can usefputs
counterparts with thestd::io::stdout()
stream to write an arbitrary byte sequence.ungetc(c,stream)
: No direct counterpart. Thestd::io::Buffer
does not allow to rollback a read, but you can peek the buffer to achieve the similar behavior. Thereforeint c = fgetc(); ungetc(c,stream); c
would 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 ofsize
bytes 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. Seeftell
below.fseek(stream,offset,whence)
:stream.seek(offset, whence)
wherewhence
is an appropriatestd::io::SeekStyle
value. This is defined in thestd::io::Seek
trait, which many streams includingFile
implement.fsetpos(stream,pos)
: No counterpart, as Rust's stream does not have the parse state. Seefseek
above.ftell(stream)
:stream.tell()
. This is defined in thestd::io::Seek
trait, which many streams includingFile
implement.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 anIoError
which the caller has to somehow check or process.feof(stream)
: Not applicable. Seeclearerr
andEOF
.ferror(stream)
: Not applicable. Seeclearerr
.perror(s)
:write!(&mut std::io::stderr(), "{}: {}", s, std::io::IoError::last_error())
. TheIoError
is 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'sdiv
and others) will simply return a tuple.EXIT_FAILURE
,EXIT_SUCCESS
: Not applicable. Rust does not have an explicitexit
function. Usestd::os::set_exit_status()
with a non-zero argument to indicate the error.RAND_MAX
: Not applicable. Rust'sstd::rand::Rng
trait provides a number of convenience methods to get a random number in the exact domain, so it would be rarely needed. Note thatRng
implementations themselves are expected to provide the fullu32
oru64
random numbers.MB_CUR_MAX
: No counterpart.
atof(nptr)
: Assuming thatT
is a floating point type,from_str::<T>(nptr).unwrap_or(0.0)
wherenptr
is a string slice. You may want to handle errors more properly.atoi(nptr)
,atol(nptr)
,atoll(nptr)
: Assuming thatT
is an integer type (signed or not),from_str::<T>(nptr).unwrap_or(0)
wherenptr
is a string slice. Again, you may want to handle errors more properly.strtod(nptr,endptr)
,strtof(nptr,endptr)
,strtold(nptr,endptr)
: No counterparts.from_str
can only parse a string as a whole.strtol(nptr,endptr)
,strtoll(nptr,endptr)
,strtoul(nptr,endptr)
,strtoull(nptr,endptr)
: No counterparts.from_str
can 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_str
though.
rand()
:std::rand::random::<int>()
. In fact, you can generate other types thanint
as long as it implementsstd::rand::Rand
trait. Also, if you want to generate an integer betweenlow
tohigh
(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::rand
and 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 keepsize
andalignment
known.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_size
andalignment
known.std::rt::heap::reallocate_inplace
is 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::TaskBuilder
instead.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)
: Givenstring
is"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::Process
value 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'sbsearch
method expects a function which returns theOrdering
ofv
against (the implicit)key
(the opposite of what C'sbsearch
expects). Rust's closure would simplify the actual code a lot; for example, in order to find42
fromVec<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 defaultOrd
trait. Note that some types comparable in C are not comparable in Rust, e.g.f32
orf64
. 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 thats1
ands2
does 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; seestrcpy
for 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)
. Ifs2
is an ownedString
orVec<u8>
and you wouldn't uses2
later,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; seestrcat
for 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))
. Ifn
equates tos2.len()
(i.e. iss2
a prefix ofs1
), there is a shorters1.starts_with(s2)
. As noted above, you wouldn't normally use this for Unicode strings; seestrcmp
for more natural usages. - For raw pointers, convert
s1
ands2
withstd::slice::raw::buf_as_slice
and 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))
whereCString
isstd::c_str::CString
. In fact, you can wrap a raw buffer withCString
to 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 forn
not 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; seestrchr
for more natural usages. - For byte vectors,
s.slice_to(n).iter().position(|&v| v == c)
. - For raw pointers, convert
s
withstd::slice::raw::buf_as_slice
and 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
s
withstd::c_str::CString
and treat it as like a byte vector. (Seestrcmp
for 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 ofs1
instead. Ifs2
is 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
s1
ands2
withstd::c_str::CString
and treat them as like byte vectors. (Seestrcmp
for an example.)
- For Unicode strings,
strpbrk(s1,s2)
:- For Unicode strings,
s1.find(|c| s2.contains(c))
. The same note asstrcspn
applies. - For byte vectors,
s1.iter().position(|&c| s2.contains(&c))
. - For raw pointers, convert
s1
ands2
withstd::c_str::CString
and treat them as like byte vectors. (Seestrcmp
for 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
s
withstd::c_str::CString
and treat it as like a byte vector. (Seestrcmp
for an example.)
- For Unicode strings,
strspn(s1,s2)
:- For Unicode strings,
s1.find(|c| s2.contains(c)).unwrap_or(s1.len())
. The same note asstrcspn
applies. - For byte vectors,
s1.iter().position(|&c| s2.contains(&c)).unwrap_or(s1.len())
. - For raw pointers, convert
s1
ands2
withstd::c_str::CString
and treat them as like byte vectors. (Seestrcmp
for 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
s2
at each call,for part in s1.split(|c| s2.contains(c)) { ... }
will give each slice topart
. The same note asstrcspn
applies. - For byte vectors with the same
s2
at 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
s2
at 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
s1
ands2
withstd::c_str::CString
and treat them as like byte vectors. (Seestrcmp
for 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
n
times, 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_ITERATIONS
cnd_t
thrd_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 globalname
used to access the task-local value of typetype
.mtx_t
tss_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_plain
mtx_recursive
mtx_timed
thrd_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)
.func
can 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
).thr
is not applicable (seethrd_t
above), andarg
should be moved from the outer environment tofunc
procedure. Note that there is no strong guarantee on the beginning of new task; usestd::sync::Barrier
to ensure that.thrd_current()
: Not applicable; seethrd_t
above.thrd_detach(thr)
: Not applicable; seethrd_join
below.thrd_equal(thr0,thr1)
: Not applicable; seethrd_t
above.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_join
for 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 offunc
on success, so it can be used as a substitute ofthrd_exit
as well.thrd_sleep(duration,remaining)
:std::io::timer::sleep(duration)
withduration
in milliseconds. Rust task cannot be interrupted otherwise stated, soremaining
is 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 implementingDrop
trait; the runtime is responsible for destroying any initialized task-local values on the task exit.tss_delete(key)
:key.replace(None)
. Note thatkey
still remains usable; this would only remove the value out of the storage.tss_get(key)
:key.get()
. It may returnNone
when 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 toclock
use 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_sec
field) can be used in place oftime_t
struct timespec
:time::Timespec
.tv_sec
andtv_nsec
fields are renamed tosec
andnsec
respectively.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 / 1e9
will return the number of seconds between twotime::Timespec
s.mktime(timeptr)
:timeptr.to_timespec().sec
. Note that this does not handle the error (in which casemktime
would return-1
) correctly.time(timer)
:time::get_time().sec
.timer
is redundant.timespec_get(ts,base)
:time::get_time()
whenbase
equals toTIME_UTC
. No counterpart otherwise.
asctime(timeptr)
:timeptr.asctime()
. This is safe across multiple calls to it.ctime(timer)
:time::at(timer).asctime()
wheretimer
is atime::Timespec
.gmtime(timer)
:time::at_utc(timer)
wheretimer
is atime::Timespec
.localtime(timer)
:time::at(timer)
wheretimer
is atime::Timespec
.strftime(s,maxsize,format,timeptr)
:timeptr.strftime(format)
with the sameformat
as C. It returns a fully allocatedString
and thusmaxtime
is redundant.