To get the actual struct size, use struct.calcsize():
>>> import struct
>>> struct.calcsize('icic')
13
That's because you are using the default alignment, and then C rules are applied:
By default, C types are represented in the machine’s native format and byte order, and properly aligned by skipping pad bytes if necessary (according to the rules used by the C compiler).
The first ic would be just 5 bytes, but C would pad that out to 8 if you list it twice, so the next ic pair brings it to 13. If you used 3 ic pairs you'd get to 21, etc. C pads out the i integers to align to 4-byte groups. This data structure alignment is used to improve memory performance, but can be unexpected when trying to use it for different purposes.
Pick an explicit byte order instead:
>>> struct.calcsize('>icic')
10
See the Byte Order, Size and Alignment section.
struct.pack('icic', 1, '\t', 2, '\n')itself?'\x01\x00\x00\x00\t\x00\x00\x00\x02\x00\x00\x00\n'which means 4 bytes (little endian) for the 1, 4 bytes for the\t, 4 bytes (LE) for the 2 and one byte for the\n. And this, in turn means, three 0-bytes are inserted after the\t. If you have a look at this, you get some steps further.>prefix. In this case, you have the byte order you wand, and you get no fill bytes.