Skip to content

Instantly share code, notes, and snippets.

@lifthrasiir
Last active September 16, 2021 13:30
Show Gist options
  • Save lifthrasiir/e021349c1d0cd55933a5 to your computer and use it in GitHub Desktop.
Save lifthrasiir/e021349c1d0cd55933a5 to your computer and use it in GitHub Desktop.
C11 standard library to Rust standard library (as of 2014-07-19 nightly)

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 convert String or Vec<T> to a slice with .as_slice() method.

<assert.h>

  • assert(cond): assert!(cond) macro. Note that it's always enabled; if you need to selectively disable the assertions, use debug_assert!(cond) macro.
  • static_assert(cond, err): In the limited fashion, #[static_assert] static ANY_NAME: bool = cond; will raise a compile-time error when cond evaluates to false. Since it is a static item, cond is severely limited and cannot make any function call.

<complex.h>

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).

Trigonometric functions

  • cacos*(z): No counterparts.
  • casin*(z): No counterparts.
  • catan*(z): No counterparts.
  • ccos*(z): No counterparts.
  • csin*(z): No counterparts.
  • ctan*(z): No counterparts.

Hyperbolic functions

  • cacosh*(z): No counterparts.
  • casinh*(z): No counterparts.
  • catanh*(z): No counterparts.
  • ccosh*(z): No counterparts.
  • csinh*(z): No counterparts.
  • ctanh*(z): No counterparts.

Exponential and logarithmic functions

  • cexp*(z): No counterparts.
  • clog*(z): No counterparts.

Power and absolute-value functions

  • cabs*(z): z.norm().
  • cpow*(x,y): No counterparts.
  • csqrt*(z): No counterparts.

Manipulation functions

  • carg*(z): z.arg().
  • cimag*(z): z.im.
  • conj*(z): z.conj().
  • cproj*(z): No counterparts.
  • creal*(z): z.re.

<ctype.h>

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() for Ascii. No counterpart in char, but you can use c == ' ' || 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() for char. No counterpart in Ascii, but you can use c == 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() for Ascii. For char, 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.

<errno.h>

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(). Use std::io::IoError::last_error() for converting it to a standard I/O error type.

<fenv.h>

I believe that Rust standard library does not have any counterparts to this header file.

<float.h>

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. Technically f32 and f64 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 what DIGITS actually means yet.
  • DECIMAL_DIG: If you really want this, use std::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 that MIN_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.

<inttypes.h>

  • imaxdiv_t: No counterpart. See below.

Macros for format specifiers

  • PRI* macros: format! and related macros eliminate the needs for such macros. Just use {}, {:x} etc.
  • SCN* macros: No counterparts.

Functions for greatest-width integer types

  • imaxabs(j), imaxdiv(numer,denom), {str,wcs}to{i,u}max(nptr,endptr,base): No counterparts. Rust does not have an intmax_t or uintmax_t type (though i64 and u64 are likely the largest integer types).

<iso646.h>

Not applicable.

<limits.h>

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's char maps to char or u8/i8 in Rust, and the number of bits in u8/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 }.

<locale.h>

I believe that Rust standard library does not have any counterparts to this header file.

<math.h>

Most of the methods mentioned before are in the std::num::Signed, std::num::Float and std::num::FloatMath traits.

  • HUGE_VAL*: Use INFINITY instead.
  • INFINITY: std::<type>::INFINITY (where <type> is either f32 or f64), or std::num::Float::infinity().
  • NAN: std::<type>::NAN, or std::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 type std::num::FPCategory.
  • FP_FAST_FMA*: No counterparts.
  • FP_ILOGB0, FP_ILOGBNAN: No counterparts.
  • MATH_ERRNO, MATH_ERREXCEPT, math_errhandling: No counterparts.

Classification macros

  • 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.

Trigonometric functions

  • 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().

Hyperbolic functions

  • acosh*(x): x.acosh().
  • asinh*(x): x.asinh().
  • atanh*(x): x.atanh().
  • cosh*(x): x.cosh().
  • sinh*(x): x.sinh().
  • tanh*(x): x.tanh().

Exponential and logarithmic functions

  • exp*(x): x.exp().
  • exp2*(x): x.exp2().
  • expm1*(x): x.exp_m1().
  • frexp*(value,exp): value.frexp(). The original return value and exp 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() for iptr.
  • scalbn*(x,n), scalbln*(x,n): No counterparts. { let (frac,exp) = x.frexp(); frac.ldexp(exp + n) } can be used as an workaround.

Power and absolute-value functions

  • cbrt*(x): x.cbrt().
  • fabs*(x): x.abs() or std::num::abs(x).
  • hypot*(x,y): x.hypot(y).
  • pow*(x,y): x.powf(y) or std::num::pow(x,y).
  • sqrt*(x): x.sqrt().

Error and gamma functions

  • erf*(x): No counterparts.
  • erfc*(x): No counterparts.
  • lgamma*(x): No counterparts.
  • tgamma*(x): No counterparts.

Nearest integer functions

  • 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().

Remainder functions

  • fmod*(x,y): x % y.
  • remainder*(x,y): No counterparts.
  • remquo*(x,y): No counterparts.

Manipulation functions

  • 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.

Maximum, minimum, and positive difference functions

  • fdim*(x,y): x.abs_sub(y) or std::num::abs_sub(x, y).
  • fmax*(x,y): x.max(y). Note that floating point types do not implement the Ord trait due to the presence of NaNs, so std::cmp::max(x,y) cannot be used.
  • fmin*(x,y): x.min(y). The same note applies.

Floating multiply-add

  • fma*(x,y,z): x.mul_add(y, z).

Comparison macros

  • 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.

<setjmp.h>

I believe that Rust standard library does not have any counterparts to this header file.

<signal.h>

  • sig_atomic_t: The std::sync::atomics module provides a number of atomic primitive types.
  • SIG_DFL, SIG_ERR, SIG_IGN: Not applicable.
  • SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM: The libc crate has statics for them, which can be used in std::io::process::Process::signal for example. For the use in std::io::signal::Listener (see below), STDINT also has std::io::signal::Interrupt.

Specify signal handling

  • signal(sig,func): No direct counterpart. std::io::signal::Listener provides a safe interface around it, but it does not execute the interrupts asynchronously.

Send signal

  • raise(sig): No counterpart.

<stdalign.h>

  • alignas(align): No counterpart. Structures can have the #[packed] attribute which is effectively equivalent to alignas(1) in every field though.
  • alignof(type): std::mem::align_of::<type>().

<stdarg.h>

No counterparts. Rust supports the call to the external function with variadic arguments, but there is no support for manipulating va_list.

<stdatomic.h>

<stdbool.h>

Rust has the built-in bool type and true and false values.

<stddef.h>

  • 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, use char.
  • NULL: std::ptr::null() or std::ptr::mut_null(), depending on the underlying raw pointer type (*const T or *mut T). For the pure Rust, use an explicit Option type and None.
  • offsetof(type,member): No counterpart.

<stdint.h>

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;.

Integer types

  • 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.

Limits of specified-width integer types

  • 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.

Limits of other integer types

  • 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.

Macros for integer constants

  • 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.

<stdio.h>

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 like read_line depend on it), std::io::Writer (write-only) or std::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. See setvbuf below.
  • BUFSIZ: Not applicable. See setvbuf below.
  • EOF: The end of file is indicated with a dedicated std::io::IoError value with its kind being std::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 type std::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 normal print! or println! macro instead of stdout. Also note that they are already buffered, use std::io::stderr_raw() and so on to get the raw stream (see also setvbuf below).

Operations on files

  • remove(filename): std::io::fs::unlink(filename). If filename is not a Path, use &Path::new(filename) instead of filename.
  • rename(old,new): std::io::fs::rename(old, new). The same note as remove applies.
  • tmpfile(): No counterpart. std::io::TempDir (which creates a temporary directory) can be used to achieve the similar thing.
  • tmpnam(s): No counterpart. See tmpfile above.

File access functions

  • fclose(stream): Automatically closed on the end of scope. Use drop(stream) to explicitly deallocate the stream.
  • fflush(stream): stream.flush().
  • fopen(filename,mode): std::io::File::open_mode(filename, mode, access) with an appropriate mode and access value. The common values are Open/Read for "r" and Truncate/Write for "w"; File::open(filename) and File::create(filename) are provided as shortcuts. If filename is not a Path, use &Path::new(filename) instead of filename.
  • freopen(filename,mode,stream): No counterpart.
  • setbuf(stream,buf): No direct counterpart when buf is not NULL. See setvbuf otherwise.
  • setvbuf(stream,buf,mode,size): No direct counterpart when buf is not NULL. 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 how stream would behave after setvbuf(stream,NULL,_IOLBF,BUFSIZ).
    • std::io::BufferedReader::new(stream) is similar to how stream would behave after setvbuf(stream,NULL,_IOFBF,BUFSIZ).
    • std::io::BufferedReader::with_capacity(size, stream) is similar to how stream would behave after setvbuf(stream,NULL,_IOFBF,size).
    • Similarly, there are std::io::BufferedWriter and std::io::BufferedStream for Writer and Stream.

Formatted input/output functions

  • fprintf(stream,format,...): write!(stream, format, ...). stream should be of the type &mut Writer, and format 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 the std::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, the regex crate and from_str can do many of things possible with sscanf.
  • printf(format,...): print!(format, ...), or println!(format, ...) if format ends with \n. The same note as fprintf applies.
  • scanf(format,...): No counterpart. See fscanf.
  • snprintf(s,n,format,...): You normally don't need this, as n is mostly to stop the buffer overflow. See sprintf.
  • sprintf(s,format,...): format!(format, ...). The same note as fprintf applies. This returns String and very safe from the buffer overflow unlike the original C function.
  • sscanf(s,format,...): No counterpart. See fscanf.
  • vfprintf(stream,format,arg): No direct counterpart, as va_list is not supported. If you want to make your own formatting function, you'd better writing a macro over format_args!(|args| std::fmt::write(stream, args), ...); see the std::fmt documentation for details.
  • vfscanf(stream,format,arg): No counterpart. See fscanf.
  • vprintf(format,arg): No direct counterpart, but you can write a macro over format_args!(std::io::stdio::print_args, ...). See vfprintf.
  • vscanf(format,arg): No counterpart. See fscanf.
  • vsnprintf(s,n,format,arg): You normally don't need this, as n is mostly to stop the buffer overflow. See sprintf.
  • vsprintf(s,format,arg): No direct counterpart, but you can write a macro over format_args!(std::fmt::format, ...). See vfprintf.
  • vsscanf(s,format,arg): No counterpart. See fscanf.

Character input/output functions

  • fgetc(stream): stream.read_char() to get a char, stream.read_byte() to get a u8. The former only works for Buffer, so the raw stream has to be converted to the buffered reader (see setvbuf above).
  • fgets(s,n,stream): stream.read_at_least(1, n, &mut s) where s is a Vec<u8>. There are a family of related methods in Reader.
  • fputc(c,stream): stream.write_char(c) to write a char (as a UTF-8 string), stream.write_u8(c) to write a u8.
  • fputs(s,stream): stream.write_str(s) to write a Unicode string, stream.write(s) to write a byte buffer.
  • getc(stream): See fgetc.
  • getchar(): Use fgetc counterparts with the std::io::stdin() stream. You may want to keep the resulting stream to avoid redundant allocations.
  • putc(c,stream): See fputc.
  • putchar(c): print!("{}", c) to write a char (as a UTF-8 string). It is not desirable to write a raw byte to the standard output, but you can use fputc counterparts with the std::io::stdout() stream.
  • puts(s): print!("{}", s) or print!("...") (for the fixed s) to write a Unicode string. Again, you can use fputs counterparts with the std::io::stdout() stream to write an arbitrary byte sequence.
  • ungetc(c,stream): No direct counterpart. The std::io::Buffer does not allow to rollback a read, but you can peek the buffer to achieve the similar behavior. Therefore int c = fgetc(); ungetc(c,stream); c would translate to stream.fill_buf().map(|buf| buf[0]).

Direct input/output functions

  • 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 of size 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 or size-byte elements actually written however.

File positioning functions

  • fgetpos(stream,pos): No counterpart, as Rust's stream does not have the parse state. See ftell below.
  • fseek(stream,offset,whence): stream.seek(offset, whence) where whence is an appropriate std::io::SeekStyle value. This is defined in the std::io::Seek trait, which many streams including File implement.
  • fsetpos(stream,pos): No counterpart, as Rust's stream does not have the parse state. See fseek above.
  • ftell(stream): stream.tell(). This is defined in the std::io::Seek trait, which many streams including File implement.
  • rewind(stream): stream.seek(0, std::io::SeekSet).

Error-handling functions

  • clearerr(stream): Not applicable. Rust's stream does not have an associated error state, and every operation to the stream may return an IoError which the caller has to somehow check or process.
  • feof(stream): Not applicable. See clearerr and EOF.
  • ferror(stream): Not applicable. See clearerr.
  • perror(s): write!(&mut std::io::stderr(), "{}: {}", s, std::io::IoError::last_error()). The IoError is more commonly retrieved from the return value of I/O operations though.

<stdlib.h>

  • div_t, ldiv_t, lldiv_t: Not applicable. std::num::div_rem (a counterpart to C's div and others) will simply return a tuple.
  • EXIT_FAILURE, EXIT_SUCCESS: Not applicable. Rust does not have an explicit exit function. Use std::os::set_exit_status() with a non-zero argument to indicate the error.
  • RAND_MAX: Not applicable. Rust's std::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 that Rng implementations themselves are expected to provide the full u32 or u64 random numbers.
  • MB_CUR_MAX: No counterpart.

Numeric conversion functions

  • atof(nptr): Assuming that T is a floating point type, from_str::<T>(nptr).unwrap_or(0.0) where nptr is a string slice. You may want to handle errors more properly.
  • atoi(nptr), atol(nptr), atoll(nptr): Assuming that T is an integer type (signed or not), from_str::<T>(nptr).unwrap_or(0) where nptr 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 to from_str though.

Pseudo-random sequence generation functions

  • rand(): std::rand::random::<int>(). In fact, you can generate other types than int as long as it implements std::rand::Rand trait. Also, if you want to generate an integer between low to high (exclusive), use std::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 from std::rand and use std::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.

Memory management functions

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 appropriate alignment.
  • free(ptr): Safe types get automatically deallocated at the end of scope. If you want to be explicit, though, you can use drop(ptr). For the raw memory allocated with std::rt::heap::allocate, use std::rt::heap::deallocate(ptr, size, alignment); you need to keep size and alignment known.
  • malloc(size): std::rt::heap::allocate(size, alignment) with an appropriate alignment.
  • realloc(ptr,size): std::rt::heap::reallocate(ptr, size, alignment, old_size); again, you need to keep old_size and alignment known. std::rt::heap::reallocate_inplace is similar but tries to keep the original pointer and returns false if impossible.

Communication with the environment

  • abort(): Use fail!() to terminate the current task. You can also use core::intrinsics::abort() with extern 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 by std::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 use std::os::getenv_as_bytes(name) to get the original byte vector.
  • quick_exit(status): No counterpart.
  • system(string): Given string is "program arg1 ... argN", use std::io::Command::new("program").arg("arg1")...arg("argN").spawn(). (If the string is dynamic, use string.words().to_vec() to get a vector of arguments.) This returns an std::io::process::Process value used to control the child process.

Searching and sorting utilities

  • bsearch(key,base,nmemb,size,compar): base.slice_to(nmemb).bsearch(|v| 0.cmp(&compar(&key, v))). In the other words, Rust's bsearch method expects a function which returns the Ordering of v against (the implicit) key (the opposite of what C's bsearch expects). Rust's closure would simplify the actual code a lot; for example, in order to find 42 from Vec<uint>, use vec.bsearch(|v| v.cmp(&42u)).
  • qsort(base,nmemb,size,compar): base.mut_slice_to(nmemb).sort_by(|a,b| compar(a, b).cmp(&0)), or base.mut_slice_to(nmemb).sort() to use the default Ord trait. Note that some types comparable in C are not comparable in Rust, e.g. f32 or f64. Again, the actual code is much simpler; for example, in order to sort by a particular field, use vec.sort_by(|a, b| a.foo.cmp(&b.foo)).

Integer arithmetic functions

  • abs(j), labs(j), llabs(j): j.abs().
  • div(numer,denom), ldiv(numer,denom), lldiv(numer,denom): std::num::div_rem(numer, denom).

Multibyte/wide character conversion functions

  • mblen(s,n):
  • mbtowc(pwc,s,n)
  • wctomb(s,wc)

Multibyte/wide string conversion functions

  • mbstowcs(pwcs,s,n)
  • wcstombs(s,pwcs,n)

<stdnoreturn.h>

C's noreturn attribute is akin to Rust's -> ! return type.

<string.h>

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.

Copying functions

  • 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 that s1 and s2 does not overlap).
    • For raw pointers, std::ptr::copy_memory(s1, s2, n).
  • strcpy(s1,s2):
    • For Unicode strings, s1 = s2.as_slice() or s1 = s2.to_string() depending on the type of s1.
    • For byte vectors, s1 = s2.as_slice() or s1 = s2.to_vec() depending on the type of s1.
    • For raw pointers, there is no direct counterpart. Use an explicit loop.
  • strncpy(s1,s2,n):
    • For Unicode strings, s1 = s2.slice_to(n) or s1 = s2.slice_to(n).to_string() depending on the type of s1. As noted above, you wouldn't normally use this; see strcpy for more natural usages.
    • For byte vectors, s1 = s2.slice_to(n) or s1 = s2.slice_to(n).to_vec() depending on the type of s1.
    • For raw pointers, there is no direct counterpart. Use an explicit loop.

Concatenation functions

  • strcat(s1,s2):
    • For Unicode strings and byte vectors, s1.push_all(s2). If s2 is an owned String or Vec<u8> and you wouldn't use s2 later, s1.push_all_move(s2) can also be used.
    • For raw pointers, there is no direct counterpart. Use an explicit loop.
  • 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; see strcat for more natural usages.
    • For raw pointers, there is no direct counterpart. Use an explicit loop.

Comparison functions

  • memcmp(s1,s2,n):
    • For Unicode strings and byte vectors, s1.slice_to(n).cmp(&s2.slice_to(n)). If n equates to s2.len() (i.e. is s2 a prefix of s1), there is a shorter s1.starts_with(s2). As noted above, you wouldn't normally use this for Unicode strings; see strcmp for more natural usages.
    • For raw pointers, convert s1 and s2 with std::slice::raw::buf_as_slice and treat them as like 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)) where CString is std::c_str::CString. In fact, you can wrap a raw buffer with CString to use it like a normal byte vector.
  • strcoll(s1,s2): No counterpart.
  • strncmp(s1,s2,n): Same as memcmp, except that one should be careful for n not to exceed s1.len() or s2.len().
  • strxfrm(s1,s2,n): No counterpart.

Search functions

  • 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; see strchr for more natural usages.
    • For byte vectors, s.slice_to(n).iter().position(|&v| v == c).
    • For raw pointers, convert s with std::slice::raw::buf_as_slice and treat it as like a byte vector.
  • 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 with std::c_str::CString and treat it as like a byte vector. (See strcmp for an example.)
  • 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 in s2, and if there is none, use the length of s1 instead. If s2 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 and s2 with std::c_str::CString and treat them as like byte vectors. (See strcmp for an example.)
  • strpbrk(s1,s2):
    • For Unicode strings, s1.find(|c| s2.contains(c)). The same note as strcspn applies.
    • For byte vectors, s1.iter().position(|&c| s2.contains(&c)).
    • For raw pointers, convert s1 and s2 with std::c_str::CString and treat them as like byte vectors. (See strcmp for an example.)
  • 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 with std::c_str::CString and treat it as like a byte vector. (See strcmp for an example.)
  • strspn(s1,s2):
    • For Unicode strings, s1.find(|c| s2.contains(c)).unwrap_or(s1.len()). The same note as strcspn applies.
    • For byte vectors, s1.iter().position(|&c| s2.contains(&c)).unwrap_or(s1.len()).
    • For raw pointers, convert s1 and s2 with std::c_str::CString and treat them as like byte vectors. (See strcmp for an example.)
  • strstr(s1,s2):
    • For Unicode strings, s1.find_str(s2).
    • There are no counterparts for other cases.
  • 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 to part. The same note as strcspn applies.
    • For byte vectors with the same s2 at each call, for part in s1.split(|&c| s2.contains(&c)) { ... } will give each slice to part.
    • 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 (see strchr), use a slice up to that position, set the current slice to a portion after the separator and continue.
    • For raw pointers, convert s1 and s2 with std::c_str::CString and treat them as like byte vectors. (See strcmp for an example.)

Miscellaneous functions

  • memset(s,c,n):
    • Unicode strings cannot be directly manipulated. If you need a string with the same character repeated n times, use c.to_string().repeat(n).
    • For byte vectors, s.mut_slice_to(n).set_memory(c). It needs use std::slice::bytes::MutableByteVector;.
    • For raw pointers, std::ptr::set_memory(s, c, n).
  • 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().

<tgmath.h>

Rust's mathematical functions are based on a number of traits, and consequently, automatically type-general. See <math.h>.

<threads.h>

  • thread_local: #[thread_local] attribute. Normally you don't need this (unless you need to link with the external library using it); see tss_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 global name used to access the task-local value of type type.
  • mtx_t
  • tss_dtor_t: No direct counterpart; see tss_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).

Initialization functions

  • call_once(flag,func): flag.doit(func). func can be any closure, i.e. it can refer to the calling environment.

Condition variable functions

  • cnd_broadcast(cond)
  • cnd_destroy(cond)
  • cnd_init(cond)
  • cnd_signal(cond)
  • cnd_timedwait(cond,mtx,ts)
  • cnd_wait(cond,mtx)

Mutex functions

  • mtx_destroy(mtx)
  • mtx_init(mtx,type)
  • mtx_lock(mtx)
  • mtx_timedlock(mtx,ts)
  • mtx_trylock(mtx)
  • mtx_unlock(mtx)

Thread functions

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 also thrd_join). thr is not applicable (see thrd_t above), and arg should be moved from the outer environment to func procedure. Note that there is no strong guarantee on the beginning of new task; use std::sync::Barrier to ensure that.
  • thrd_current(): Not applicable; see thrd_t above.
  • thrd_detach(thr): Not applicable; see thrd_join below.
  • thrd_equal(thr0,thr1): Not applicable; see thrd_t above.
  • thrd_exit(res): The task body can return or fail (via fail! and many other means) to terminate the current task. Any resource allocated over the course is safely destroyed even on the failure. See thrd_join for how to return an arbitrary res (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 via std::task::try(func). Its return value contains a return value of func on success, so it can be used as a substitute of thrd_exit as well.
  • thrd_sleep(duration,remaining): std::io::timer::sleep(duration) with duration in milliseconds. Rust task cannot be interrupted otherwise stated, so remaining is not applicable.
  • thrd_yield(): std::task::deschedule().

Thread-specific storage functions

  • tss_create(key,dtor): This is implicit (the task-local storage is initialized with None). For a non-null dtor, use a custom type implementing Drop trait; the runtime is responsible for destroying any initialized task-local values on the task exit.
  • tss_delete(key): key.replace(None). Note that key still remains usable; this would only remove the value out of the storage.
  • tss_get(key): key.get(). It may return None when the storage is empty.
  • tss_set(key,val): key.replace(Some(val)). It would move the previous value out of the storage.

<time.h>

All of the following types and functions needs extern crate time; in Rust.

  • CLOCKS_PER_SEC: No counterpart. Two counterparts to clock use the fixed unit (seconds and nanoseconds respectively) though.
  • TIME_UTC: No counterpart; see timespec_get.
  • clock_t: No counterpart; see clock.
  • time_t: No counterpart, but struct timespec (and its tv_sec field) can be used in place of time_t
  • struct timespec: time::Timespec. tv_sec and tv_nsec fields are renamed to sec and nsec respectively.
  • struct tm: time::Tm. Field names remain unchanged.

Time manipulation functions

  • clock(): time::precise_time_s() (in seconds) or time::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 two time::Timespecs.
  • mktime(timeptr): timeptr.to_timespec().sec. Note that this does not handle the error (in which case mktime would return -1) correctly.
  • time(timer): time::get_time().sec. timer is redundant.
  • timespec_get(ts,base): time::get_time() when base equals to TIME_UTC. No counterpart otherwise.

Time conversion functions

  • asctime(timeptr): timeptr.asctime(). This is safe across multiple calls to it.
  • ctime(timer): time::at(timer).asctime() where timer is a time::Timespec.
  • gmtime(timer): time::at_utc(timer) where timer is a time::Timespec.
  • localtime(timer): time::at(timer) where timer is a time::Timespec.
  • strftime(s,maxsize,format,timeptr): timeptr.strftime(format) with the same format as C. It returns a fully allocated String and thus maxtime is redundant.

<uchar.h>

<wchar.h>

<wctype.h>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment