# COP and CPS — Copy

Source: https://rungs.dev/docs/structured-text/instructions/cop-cps

> COP and CPS are the Structured Text instructions in rungs.dev that copy a run of elements from one array into another, clamped to whichever array runs out first.

Copies a run of elements from one array into another, stopping at whichever array runs out
first. Modeled on the COP and CPS instructions in Logix 5000® controllers.

```iecst
COP(Samples[0], Snapshot[0], 10);
```

After this statement, the first ten elements of `Samples` have been copied into `Snapshot`.

`CPS` is the same copy with a guarantee: nothing else touches the data while it runs. On a real
controller that matters, because an input module can update a tag between one element and the
next. Studio runs one thing at a time, so the two behave identically here.

## Operands [#operands]

| Name     | Type                                                                   | Notes                                                |
| -------- | ---------------------------------------------------------------------- | ---------------------------------------------------- |
| `source` | `DINT`, `INT`, `SINT`, `REAL`, `STRING`, `TIMER`, `COUNTER`, `CONTROL` | One element — `Samples[0]`, or a whole scalar tag    |
| `dest`   | `DINT`, `INT`, `SINT`, `REAL`, `STRING`, `TIMER`, `COUNTER`, `CONTROL` | Where it goes. Also one element                      |
| `length` | `DINT`, `INT` or `SINT`                                                | How many **destination** elements. A tag or a number |

Both operands must name a single element, never the bare array name. The element you name is
where the run **starts**, so `COP(Samples[2], Snapshot[0], 3)` copies elements 2, 3 and 4.

A `STRING` copies as its 88 bytes: `.LEN` as four bytes, lowest first, then the 82 bytes of
`.DATA`, then two spare bytes. So `COP(Reply[0], Msg, 1);` turns a `SINT` buffer into text,
taking `.LEN` from its first four bytes.

To move only the characters, name the first one: `COP(Reply[0], Msg.DATA[0], Count);` copies
`Count` bytes into `.DATA` and leaves `.LEN` as it was, so set it next, with
`Msg.LEN := Count;`. The copy runs on through the two spare bytes and stops only at the end of
the `STRING`, or of the whole array when `Msg` is an element of one.

## How many elements actually move [#how-many-elements-actually-move]

`length` counts destination elements, and the copy stops at whichever tag runs out first. None
of these is an error:

| What you wrote                         | What happens                       |
| -------------------------------------- | ---------------------------------- |
| `length` fits both arrays              | That many elements copy            |
| `length` bigger than either array      | Copies as much as fits, then stops |
| `length` of `0`                        | Copies nothing                     |
| `length` from a tag holding a negative | Copies the whole remaining run     |

The count is worked out in bytes without a sign, which is why a negative length copies
everything rather than nothing.

## Copying between different types [#copying-between-different-types]

`COP` moves **raw bytes** — it does not convert. Copying a `DINT` array into a `REAL` array
gives the bit patterns read as floats. That is how you pack four `SINT`s into one `DINT`, or
unpack a device word into bytes.

For a converted copy of one value, use an assignment instead:

```iecst
Snapshot[0] := Samples[0];
```

## Common Mistakes [#common-mistakes]

- Writing `COP(Samples, Snapshot, 5)`. Name one element: `Samples[0]`.
- Expecting a `DINT` → `REAL` copy to convert. It reinterprets the bits.
- Using the result in an expression. `COP` returns nothing; it is a statement on its own.

## Related [#related]

- [SIZE](https://rungs.dev/docs/structured-text/instructions/size) — how many elements an array has
- [Arrays](https://rungs.dev/docs/tags/arrays) — declaring one
- [COP and CPS in Ladder](https://rungs.dev/docs/ladder-logic/instructions/cop-cps)