Memory Addresses
Introduction
Memory Addresses - Topics
- View addresses of local variables and heap variables
- Stack protocol for locals
- Heap reuse
- See two ways to view addresses: attribute 'address and values of access types
- Also consider pointers in other languages
How to Print Addresses
- How to print, using Address Attribute:
- Attribute 'Address returns the address of a variable
- System.Address_Image converts an address into a string
with System.Address_Image;
i: Integer;
...
put_line("Address of i: " & System.Address_Image(i'address));
Printing Values of Access Types:
- We will convert a value of an access type into a type that we can print
Printing Addresses with Address Attribute
Printing Addresses
Printing Values of Access Types - SKIP
Printing Access Types
- How do we print values of Access Types,
- Problem: No I/O routine for them
- Possible solution: Convert access type to an int
-
No - Integer range is about 2^-31 .. 2^31. Address range is about 0 .. 2^32.
- Solution: Define a type for 32-bit addresses and convert an access type to that type
- Use modular types for the type
- Use Unchecked_Conversion to convert an access type into the modular type
Modular Types
- Example modular type: minutes.adb
(prettified)
- Values of type
minuteType
range from 0 to 59 and they wrap
- Arithmetic for type
minuteType
wraps
procedure minutes is
type MinuteType is mod 60;
package Minute_IO is new Text_IO.Modular_IO (Num => MinuteType);
use Minute_IO;
m: MinuteType;
begin
m := 50;
m := m + 20;
put(m); -- Outputs 10
Side Note: Modular types allow some bitwise operations such as and, or, not, xor:
type Unsigned_Byte is mod 256;
u: Unsigned_Byte := 2#0011_0101#
v: Unsigned_Byte := 2#1111_0000#
w: Unsigned_Byte := u and v;
Modular Types and Addreses
- Our motivation for looking at modular types: define a type that will allow us to
print addresses
- Addresses are 32 bits long (on a 32 bit machine)
- Addresses take values from 0 to 2**32 - 1
- The largest address (2**32-1) is 2#1111_1111_1111_1111_1111_1111_1111_1111# in binary
- Ada.Integer_Text_IO would print 2#1111_1111_1111_1111_1111_1111_1111_1111# as -1
rather than as a large integer
- We use a Modular Type to hold 32 bit addresses
type AddressType is mod 2**32;
We use generic package modular_io
to define an io package for
AddressTypes
Modular Types in Other Languages
- Other languages have something similar to modular types: unsigned types
- C: unsigned int, unsigned char
- Java: char
- Examples:
// Java
char c;
c = 97; // Ascii 'a'
c = -1; // Error
// C
unsigned int ui;
ui = -1; // Compiles fine!
// can print ui as
Converting Pointers to Our Address Type
- Generic function Unchecked_Conversion allows a program
to ignore type rules:
- Use Unchecked_Conversion to convert from a pointer type
to a modular type
- Example: Create
Copy
which takes an IntPointer
and returns an AddressType
type IntPointer is access Integer;
type AddressType is mod 2**32;
function Copy is
new Unchecked_Conversion (Source => IntPointer,
Target => AddressType);
a: IntPointer;
b: AddressType
...
b := Copy(a)
- Variable a is copied to b, even though types don't match
Example of use: printmem.adb and
prettified: printmem.adb.html
- Shows Modular Type and Unchecked_Conversion
- Shows heap addresses and reuse of heap locations
Pointing to Variables on the Stack
Pointing to Variables on the Stack
- Attribute 'access returns an access type value that points to a variable
- Special rules are required for pointing to a local variable:
- A local variable with a pointer to it must be marked as
aliased
- The type IntPointer must be defined as an access
all Integer
- Why: what happens here:
type Int_Pointer is access all Integer; -- all allows pointing to locals
procedure getaddr(ip: out Int_Pointer) is
loc: aliased integer; -- allow pointers to loc
begin
ip := loc'access;
end getaddr;
an_ip: Int_Pointer;
begin
getaddr(an_ip);
put(an_ip.all);
Remember: local variables are allocated on the stack
The code above will not compile: non-local pointer type points to local variable
See below for C code
Examples
- These examples show:
- Printing values of access types
- Pointers to local variables
- Example 1: aliasedlocal.adb (and
prettified)
- Shows addresses of locals decreasing and of heap increasing
- Also shows creation and use of a dangling reference and reallocation to same
location
- Example 2:
aliasedlocal2.adb
(and prettified)
- Shows addresses of locals in the main procedure and in a called procedure:
- Another Example):
uninitlocals.adb
(and prettified)
- Main calls putlocaladdr1 then main calls putlocaladdr2
- Both putlocaladdr1 and putlocaladdr2 share the same memory
- Variable b in putlocaladdr2 is uninitialized,
but it uses the value left in memory by putlocaladdr1
Pointers in Other Languages
Introduction
- In java and ada we get automatic dereferencing of pointer
variables; in other languages (eg c and c++), dereferencing is not
necessarily automatic.
- As an example, we will look at procedure swap in several languages
Swap in Ada and Java
procedure swap(i, j: in out integer) is
t: constant integer := i;
begin
i := j;
j := t;
end swap;
...
i := 3; j := 4;
swap(i, j);
put(i); put(j);
Swap in Java:
// Swap routine in Java
swap(int i, int j){
int temp = i;
i = j;
j = temp
S.o.p(i);
S.o.p(j);
}
// Client code:
int i=5, j=6;
...
swap(i, j); // Like in parameters
S.o.p(i);
S.o.p(j);
Pointers in C - Swap
- C makes heavy use of pointers. For example, it uses pointers to get the effect of out and in out parameters.
- C uses
int *p
to denote that p points to an integer
- C uses
*p
to dereference p
- C uses
&i
to give the address of i
- Swap example:
// Swap routine in C
swap(int *ip, int *jp){ // ip and jp are pointers to integers
int temp = *ip; // Explicit dereference of pointer ip
*ip = *jp;
*jp = temp
}
// Client code:
int i = 5, j = 6;
...
swap(&i, &j); // Pass explicit pointers to i and j
In C, pointers are also used to access arrays (example below).
Pointers in C++ - Swap
- C++ is similar to C with pointers. C++ does allow reference
mode parameters that are effectively in out mode parameters. They are automatically
passed by address and have automatic dereferencing.
// Swap routine in C++
swap(int &ip, int &jp){ // i and j are reference parameters
int temp = ip; // Automatic dereference of pointer ip
ip = jp;
jp = temp
}
// Client code:
int i=5, j=6;
...
swap(i, j); // Pass implicit pointers to i and j
Pointers in C - Arrays
int a[] = {11, 22, 33};
// Change a[2]
a[2] = 44;
// Change a[2]
*(a+2) = 55; // * means dereference. +2 means 2 words
Pointers in C - EvilPointers.c
Why Pointers
- Creating dynamic structures
- Size can grow and shrink as needed
- Examples: Dynamic stacks and queues
- Allocating heap memory
- Java objects (of any size) are on heap
- Accessing variable-sized heap objects with constant sized
references
- Makes OO and polymorphism possible
- Ada objects use pointers to avoid size issue
- Heap objects can change size
- Example: Java strings (
s="abc"; s="de";
)
- Example: Java ArrayList
- Allocate a certain size
- When run out of space, allocate more (may copy into new
space)
- Known as amortized doubling
- Parameter passing
- Can pass large or unknown-size parameters by copying reference instead of value
- Ada in out mode:
- small values copied in/out
- large values pointer is passed
- Java: Parameters that are objects are passed as
(in mode) references to those objects
- C: to change a parameter, you must pass an address (see
above)
- C++: Like c, but also have reference parameters (see above)
- Allows multiple access to an object and avoids copying
- Example: clock
- Lookup table
- Array of students
- Print queue: queue of pointers to print jobs