Host introspection: Difference between revisions
J: simplify |
|||
Line 309: | Line 309: | ||
<lang j> IF64 {;:'little big' |
<lang j> IF64 {;:'little big' |
||
little</lang> |
little</lang> |
||
This returns <code>big</code> in 64 bit J. |
|||
Note that this mechanism is testing the interpreter, and not the OS or Hardware. (Though, of course, you cannot run a 64 bit interpreter on a machine that does not support it.) |
Note that this mechanism is testing the interpreter, and not the OS or Hardware. (Though, of course, you cannot run a 64 bit interpreter on a machine that does not support it.) |
Revision as of 19:07, 24 October 2011
![Task](http://static.miraheze.org/rosettacodewiki/thumb/b/ba/Rcode-button-task-crushed.png/64px-Rcode-button-task-crushed.png)
You are encouraged to solve this task according to the task description, using any language you may know.
Print the word size and endianness of the host machine.
See also: Variable size/Get
Ada
<lang ada>with Ada.Text_IO; use Ada.Text_IO; with System; use System;
procedure Host_Introspection is begin
Put_Line ("Word size" & Integer'Image (Word_Size)); Put_Line ("Endianness " & Bit_Order'Image (Default_Bit_Order));
end Host_Introspection;</lang> Sample output on a Pentium machine:
Word size 32 Endianness LOW_ORDER_FIRST
ALGOL 68
<lang algol68>INT max abs bit = ABS(BIN 1 SHL 1)-1; INT bits per char = ENTIER (ln(max abs char+1)/ln(max abs bit+1)); INT bits per int = ENTIER (1+ln(max int+1.0)/ln(max abs bit+1));
printf(($"states per bit: "dl$,max abs bit+1)); printf(($"bits per char: "z-dl$,bits per char)); printf(($"bits per int: "z-dl$,bits per int)); printf(($"chars per int: "z-dl$,bits per int OVER bits per char));
printf(($"bits width: "z-dl$, bits width));
STRING abcds = "ABCD"; FILE abcdf; INT abcdi;
INT errno := open(abcdf, "abcd.dat",stand back channel); put(abcdf,abcds); # output alphabetically # reset(abcdf); get bin(abcdf,abcdi); # input in word byte order # STRING int byte order := ""; FOR shift FROM 0 BY bits per char TO bits per int - bits per char DO
int byte order +:= REPR(abcdi OVER (max abs bit+1) ** shift MOD (max abs char+1))
OD; printf(($"int byte order: "g,", Hex:",16r8dl$,int byte order, BIN abcdi))</lang> Output (Intel i686):
states per bit: 2 bits per char: 8 bits per int: 32 chars per int: 4 bits width: 32 int byte order: ABCD, Hex:44434241
On older CPUs the results would vary:
ALGOL 68R | ALGOL 68RS | |
~ bits per char: 6 bits per int: 24 chars per int: 4 |
ICL 2900 bits per char: 8 bits per int: 32 chars per int: 4 |
Multics bits per char: 6 bits per int: 36 chars per int: 6 |
C
<lang c>#include <stdio.h>
- include <stddef.h> /* for size_t */
- include <limits.h> /* for CHAR_BIT */
int main() {
int one = 1;
/* * Best bet: size_t typically is exactly one word. */ printf("word size = %d bits\n", (int)(CHAR_BIT * sizeof(size_t)));
/* * Check if the least significant bit is located * in the lowest-address byte. */ if (*(char *)&one) printf("little endian\n"); else printf("big endian\n"); return 0;
}</lang>
On POSIX-compatible systems, the following also tests the endianness (this makes use of the fact that network order is big endian): <lang c>#include <stdio.h>
- include <arpa/inet.h>
int main() {
if (htonl(1) == 1) printf("big endian\n"); else printf("little endian\n");
}</lang>
C#
<lang csharp>static void Main() {
Console.WriteLine("Word size = {0} bytes,",sizeof(int));
if (BitConverter.IsLittleEndian) Console.WriteLine("Little-endian."); else Console.WriteLine("Big-endian.");
}</lang>
Clojure
<lang clojure>(println "word size: " (System/getProperty "sun.arch.data.model")) (println "endianness: " (System/getProperty "sun.cpu.endian"))</lang>
Common Lisp
Common Lisp doesn't provide a native way to reliably determine this (though some unlike other languages, you rarely, if ever, need this information).
The Environment has some implementation-specific functions that might provide a good hint, e.g., <lang lisp>(machine-type) ;; => "X86-64" on SBCL here</lang>
The *features* list also provides useful information, e.g., some compilers declare :LITTLE-ENDIAN there.
The cl-trivial-features library standardizes this, so you will always get either :LITTLE-ENDIAN or :BIG-ENDIAN. It also adds the CPU (:X86, :X86-64, :PPC, :PPC64, etc.), from which you can probably derive the word size, but it's not (yet) available as a separate flag.
D
<lang d>import std.stdio, std.system;
void main() {
writefln("word size = ", size_t.sizeof * 8); writefln(endian == Endian.LittleEndian ? "little" : "big", " endian");
}</lang>
Delphi
<lang Delphi>program HostIntrospection ;
{$APPTYPE CONSOLE}
uses SysUtils;
begin
Writeln('word size: ' + IntToStr(SizeOf(Integer))); Writeln('endianness: little endian'); // Windows is always little endian
end.</lang>
Erlang
To find the word size: <lang erlang>1> erlang:system_info(wordsize). 4</lang>
In the case of endianness, Erlang's bit syntax by default has a 'native' option which lets you use what is supported natively. As such, there is no function to find endianness. However, one could write one by using bit syntax, setting endianness and then comparing to the native format:
<lang erlang>1> <<1:4/native-unit:8>>. <<1,0,0,0>> 2> <<1:4/big-unit:8>> <<0,0,0,1>> 3> <<1:4/little-unit:8>>. <<1,0,0,0>></lang>
And so the following function would output endiannes:
<lang erlang>endianness() when <<1:4/native-unit:8>> =:= <<1:4/big-unit:8>> -> big; endianness() -> little.</lang>
Factor
<lang factor>USING: alien.c-types io layouts ; "Word size: " write cell 8 * . "Endianness: " write little-endian? "little" "big" ? print</lang>
Forth
<lang forth>: endian
cr 1 cells . ." address units per cell" s" ADDRESS-UNIT-BITS" environment? if cr . ." bits per address unit" then cr 1 here ! here c@ if ." little" else ." big" then ." endian" ;</lang>
This relies on c@ being a byte fetch (4 chars = 1 cells). Although it is on most architectures, ANS Forth only guarantees that 1 chars <= 1 cells. Some Forths like OpenFirmware have explicitly sized fetches, like b@.
Fortran
<lang fortran>INTEGER, PARAMETER :: i8 = SELECTED_INT_KIND(2) INTEGER, PARAMETER :: i16 = SELECTED_INT_KIND(4) INTEGER(i8) :: a(2) INTEGER(i16) :: b
WRITE(*,*) bit_size(1) ! number of bits in the default integer type
! which may (or may not!) equal the word size
b = Z'1234' ! Hexadecimal assignment a = (TRANSFER(b, a)) ! Split a 16 bit number into two 8 bit numbers
IF (a(1) == Z'12') THEN ! where did the most significant 8 bits end up
WRITE(*,*) "Big Endian"
ELSE
WRITE(*,*) "Little Endian"
END IF</lang>
F#
A lot of research before I finally came up with an answer to this that isn't dependent on the machine it was compiled on. Works on Win32 machines only (obviously, due to the interop). I think that strictly speaking, I should be double checking the OS version before making the call to wow64Process, but I'm not worrying about it. <lang fsharp>open System open System.Runtime.InteropServices open System.Diagnostics
[<DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)>] extern bool IsWow64Process(nativeint hProcess, bool &wow64Process);
let answerHostInfo =
let Is64Bit() = let mutable f64Bit = false; IsWow64Process(Process.GetCurrentProcess().Handle, &f64Bit) |> ignore f64Bit let IsLittleEndian() = BitConverter.IsLittleEndian (IsLittleEndian(), Is64Bit())</lang>
Go
<lang go>package main
import (
"fmt" "io/ioutil" "strings" "unsafe"
)
func main() {
// inspect an int variable to determine endianness x := 1 if *(*byte)(unsafe.Pointer(&x)) == 1 { fmt.Println("little endian") } else { fmt.Println("big endian") } // inspect cpuinfo to determine word size (unix-like os only) c, err := ioutil.ReadFile("/proc/cpuinfo") if err != nil { fmt.Println(err) return } ls := strings.Split(string(c), "\n") for _, l := range ls { if strings.HasPrefix(l, "flags") { for _, f := range strings.Fields(l) { if f == "lm" { // "long mode" fmt.Println("64 bit word size") return } } fmt.Println("32 bit word size") return } } fmt.Println("cpuinfo flags not found")
}</lang> Output:
little endian 64 bit word size
Alternative technique: <lang go>package main
import (
"debug/elf" "fmt" "os"
)
func main() {
f, err := elf.Open(os.Args[0]) if err != nil { fmt.Println(" ", err) return } fmt.Println(f.FileHeader.ByteOrder) f.Close()
}</lang> Output:
LittleEndian
Groovy
Solution follows Java: <lang groovy>println "word size: ${System.getProperty('sun.arch.data.model')}" println "endianness: ${System.getProperty('sun.cpu.endian')}"</lang>
Output:
word size: 64 endianness: little
Haskell
<lang haskell>import Data.Bits import ADNS.Endian -- http://hackage.haskell.org/package/hsdns
main = do
putStrLn $ "Word size: " ++ bitsize putStrLn $ "Endianness: " ++ show endian where bitsize = show $ bitSize (undefined :: Int)</lang>
J
<lang j> IF64 {;:'little big' little</lang>
This returns big
in 64 bit J.
Note that this mechanism is testing the interpreter, and not the OS or Hardware. (Though, of course, you cannot run a 64 bit interpreter on a machine that does not support it.)
Java
Java conceals the byte order of its integers, but reports the native byte order through java.nio.ByteOrder.nativeOrder().
<lang java>import java.nio.ByteOrder;
public class ShowByteOrder {
public static void main(String[] args) { // Print "BIG_ENDIAN" or "LITTLE_ENDIAN". System.out.println(ByteOrder.nativeOrder()); }
}</lang>
Some JVMs also have system properties for the word size and byte order.
<lang java>System.out.println("word size: "+System.getProperty("sun.arch.data.model")); System.out.println("endianness: "+System.getProperty("sun.cpu.endian"));</lang>
Modula-3
<lang modula3>MODULE Host EXPORTS Main;
IMPORT IO, Fmt, Word, Swap;
BEGIN
IO.Put("Word Size: " & Fmt.Int(Word.Size) & "\n"); IF Swap.endian = Swap.Endian.Big THEN IO.Put("Endianness: Big\n"); ELSE IO.Put("Endianness: Little\n"); END;
END Host.</lang>
Output (on an x86):
Word Size: 32 Endianness: Little
NetRexx
NetRexx can access this information from the Java virtual machine in the same way as the Java sample above. <lang NetRexx>/* NetRexx */ options replace format comments java crossref savelog symbols nobinary
wordSize = System.getProperty('sun.arch.data.model') endian = System.getProperty('sun.cpu.endian')
say ' word size:' wordSize say 'endianness:' endian </lang>
Objective-C
Endianness: <lang objc>switch (NSHostByteOrder()) {
case NS_BigEndian: NSLog(@"%@", @"Big Endian"); break; case NS_LittleEndian: NSLog(@"%@", @"Little Endian"); break; case NS_UnknownByteOrder: NSLog(@"%@", @"endianness unknown"); break;
} </lang>
Architecture: Template:Works on <lang objc>switch ([NSRunningApplication currentApplication].executableArchitecture) {
case NSBundleExecutableArchitectureI386: NSLog(@"%@", @"i386 32-bit"); break;
case NSBundleExecutableArchitectureX86_64: NSLog(@"%@", @"x86_64 64-bit"); break;
case NSBundleExecutableArchitecturePPC: NSLog(@"%@", @"PPC 32-bit"); break;
case NSBundleExecutableArchitecturePPC64: NSLog(@"%@", @"PPC64 64-bit"); break;
default: NSLog(@"%@", @"Unknown"); break;
}</lang>
OCaml
<lang ocaml>Printf.printf "%d\n" Sys.word_size; (* Print word size *) Printf.printf "%s\n" Sys.os_type; (* Print operating system *)</lang>
Endianness is hidden in ocaml, but there are tricks. For example in Linux or Unix variants, one may use the uname shell command :
<lang ocaml>let uname arg =
let arg = if arg = "" then "-" else arg in let ic = Unix.open_process_in ("uname -" ^ arg) in (input_line ic)
- uname "sm";;
- : string = "Linux i686"</lang>
In most cases, endianness can be infered from informations given by uname.
One may also read files in the /proc directory in order to get informations about the host, only under linux :
<lang ocaml>(* Reading all the lines from a file. If the loop is implemented by a recursive auxiliary function, the try...with breaks tail recursion if not written carefully *) let lines name =
let f = open_in name and r = ref [] in (try while true do r := (input_line f)::!r done with End_of_file -> close_in f); (List.rev !r)
- lines "/proc/meminfo";;
- : string list = ["MemTotal: 2075240 kB"; "MemFree: 469964 kB";
"Buffers: 34512 kB"; "Cached: 1296380 kB"; "SwapCached: 96 kB"; "Active: 317484 kB"; "Inactive: 1233500 kB"; "HighTotal: 1178432 kB"; "HighFree: 45508 kB"; "LowTotal: 896808 kB"; "LowFree: 424456 kB"; "SwapTotal: 2650684 kB"; "SwapFree: 2650588 kB"; "Dirty: 228 kB"; "Writeback: 0 kB"; "AnonPages: 220036 kB"; "Mapped: 67160 kB"; "Slab: 41540 kB"; "SReclaimable: 34872 kB"; "SUnreclaim: 6668 kB"; "PageTables: 1880 kB"; "NFS_Unstable: 0 kB"; "Bounce: 0 kB"; "WritebackTmp: 0 kB"; "CommitLimit: 3688304 kB"; "Committed_AS: 549912 kB"; "VmallocTotal: 114680 kB"; "VmallocUsed: 5172 kB"; "VmallocChunk: 109320 kB"; "HugePages_Total: 0"; "HugePages_Free: 0"; "HugePages_Rsvd: 0"; "HugePages_Surp: 0"; "Hugepagesize: 4096 kB"]</lang>
Same methods can be used to get the results of commands lshw, dmidecode...
Perl
Most basic example: <lang perl>use Config; print "int size: $Config{intsize}, byte order: $Config{byteorder}\n";</lang> Example output:
int size: 4, byte order: 1234
More verbose example: <lang perl>use 5.010; use Config; my ($size, $order, $end) = @Config{qw(intsize byteorder)}; given ($order) {
when (join , sort split ) { $end = 'little' } when (join , reverse sort split ) { $end = 'big' } default { $end = 'mixed' }
} say "int size: $size, byte order: $order ($end-endian)";</lang> Example outputs:
int size: 4, byte order: 1234 (little-endian)
int size: 4, byte order: 3412 (mixed-endian)
int size: 8, byte order: 87654321 (big-endian)
PicoLisp
We inspect the ELF header of the executable file (the 'cmd' function returns the path to the command that invoked the interpreter). Note that this (like most other contributions to this task) only tells how the binary was compiled/assembled/linked, not necessarily the nature of the underlying system. <lang PicoLisp>(in (cmd) # Inspect ELF header
(rd 4) # Skip "7F" and 'E', 'L' and 'F' (prinl (case (rd 1) # Get EI_CLASS byte (1 "32 bits") (2 "64 bits") (T "Bad EI_CLASS") ) ) (prinl (case (rd 1) # Get EI_DATA byte (1 "Little endian") (2 "Big endian") (T "Bad EI_DATA") ) ) )</lang>
Output:
64 bits Little endian
PowerShell
<lang powershell>Write-Host Word Size: ((Get-WMIObject Win32_Processor).DataWidth) Write-Host -NoNewLine "Endianness: " if ([BitConverter]::IsLittleEndian) {
Write-Host Little-Endian
} else {
Write-Host Big-Endian
}</lang> Note that endianness is essentially a moot point with PowerShell, as there is only a Windows implementation currently and current Windows versions don't run on big-endian systems. But in theory this check should work.
PureBasic
<lang PureBasic>Enumeration
#LittleEndian #BigEndian
EndEnumeration
ProcedureDLL EndianTest()
Protected Endian = #LittleEndian Protected dummy.l= 'ABCD' If "A"=Chr(PeekA(@dummy)) Endian=#BigEndian EndIf ProcedureReturn Endian
EndProcedure
- - *** Start of test code
If OpenConsole()
PrintN("Your word size is "+Str(SizeOf(Integer)) +" bytes,") Select EndianTest() Case #LittleEndian PrintN("and you use Little Endian.") Default PrintN("and you use Big Endian.") EndSelect
EndIf</lang>
Python
<lang python>>>> import sys, math >>> int(round(math.log(sys.maxint,2)+1)) # this only works in Python 2.x 32 >>> import struct >>> struct.calcsize('i') * 8 32 >>> sys.byteorder little >>> import socket >>> socket.gethostname() 'PADDY3118-RESTING' >>></lang>
R
Word size <lang R>8 * .Machine$sizeof.long # e.g. 32
- or
object.size(0L) # e.g. 32 bytes</lang> Endianness <lang R>.Platform$endian # e.g. "little"</lang>
Ruby
<lang ruby># We assume that a Fixnum occupies one machine word.
- Fixnum#size returns bytes (1 byte = 8 bits).
word_size = 42.size * 8 puts "Word size: #{word_size} bits"
- Array#pack knows the native byte order. We pack 1 as a 16-bit integer,
- then unpack bytes: [0, 1] is big endian, [1, 0] is little endian.
bytes = [1].pack('S').unpack('C*') byte_order = (bytes[0] == 0 ? 'big' : 'little') + ' endian' puts "Byte order: #{byte_order}"</lang>
With MRI, ri Fixnum
states, "A Fixnum holds Integer values that can be represented in a native machine word (minus 1 bit)." This bases our claim that a Fixnum occupies one machine word.
Some other implementations of Ruby are different. With JRuby, a Fixnum is always 64 bits, because it is a Java long
(1). JRuby uses the correct native byte order by calling java.nio.ByteOrder.nativeOrder() (2).
Scheme
<lang scheme>(define host-info
(begin (display "Endianness: ") (display (machine-byte-order)) (newline) (display "Word Size: ") (display (if (fixnum? (expt 2 33)) 64 32)) (newline)))</lang>
Output:
Endianness: little-endian Word Size: 32
Slate
<lang slate>inform: 'Endianness: ' ; Platform current endianness. inform: 'Word Size: ' ; (Platform current bytesPerWord * 8) printString.</lang> Output:
Endianness: LittleEndian Word Size: 32
Tcl
This is very straightforward in Tcl. The global array tcl_platform
contains these values. In an interactive tclsh
:
<lang tcl>% parray tcl_platform
tcl_platform(byteOrder) = littleEndian
tcl_platform(machine) = intel
tcl_platform(os) = Windows NT
tcl_platform(osVersion) = 5.1
tcl_platform(platform) = windows
tcl_platform(pointerSize) = 4
tcl_platform(threaded) = 1
tcl_platform(user) = glennj
tcl_platform(wordSize) = 4</lang>
TI-89 BASIC
<lang ti89b>Disp "32-bit big-endian"</lang>