The story of porting code from C to Go and getting hooked (and to the language spec)

background

We programmers often port source code between different language processing systems. As for syntax, compiler guarantees it, so I don't really get into it.

However, for evaluation, in a similar syntax, The evaluation results may differ depending on the language, and I think that sometimes I am addicted to it.

This time, when porting from C to Go, due to differences in language specifications, Write a story that is a little addictive to getting the intended result.

"Gununu ... I transplanted it in the same way no matter how I looked at it ..."

For example, this C code

main.c


// This is main.c

#include <stdio.h>

void main () {
    unsigned char  a;
    unsigned char  b;
    unsigned short c;

    a = 0x12;
    b = 0x34;
    c = 0x0000;

    c |= (unsigned short)(a << 8);
    c |= (unsigned short)(b << 0);

    printf("c is 0x%04X\n", c);
}

I ported it to this Go code.

main.go


package main

import "fmt"

func main() {
    var a uint8
    var b uint8
    var c uint16

    a = 0x12
    b = 0x34
    c = 0x0000;

    c |= uint16(a << 8)
    c |= uint16(b << 0)

    fmt.Printf("c is 0x%04X\n", c)
}

This is a common procedure for combining the bits of two variables.

"Okay, I wrote the cast of C in the same way, No matter how you look at it, it should work from the exact same code !! "

I ran it.

$ gcc -o main.exe main.c
$ main.exe
c is 0x1234
$ go build -o main.exe
$ main.exe
c is 0x0034

"Oh ... the execution result is different ... ??"

"The C source of the porting source has the cast written properly, and Go should get angry if he doesn't have a mold or a cast in the first place ... I don't know, I don't know ... "

If you think about it later, it's not surprising (although it was actually a more complex program). I twisted my neck for about 30 minutes with this.

"Hmm ... ?? This is ..."

When I twisted my neck for 30 minutes (actually I was desperately debugging) ...

"Oh, this ʻa << 8` in C has been extended to an int." "The reason C programs work is because integer operations are implicitly extended to int ..."

"But there is no such implicit behavior in Now Go ..."

main.c


    c |= (unsigned short)(a << 8);
    c |= (unsigned short)(b << 0);

That's right. C language is the background of the times when the language was born and Because the language processing system is a CPU-dependent standard, Frequently do "undefined behavior", implicit typecasting, integral promotion, and so on.

After all, in Go, the above code is a bad code, A trivial belief delayed me from realizing why Go's code didn't work.

So the problem is that Go had to explicitly write a type extension like this:

main.go


    c |= uint16(a) << 8 //8-bit variable`<<`Type cast to a 16-bit variable before the operation is evaluated
    c |= uint16(b) << 0

The two programs are now evaluated equally.

$ gcc -o main.exe main.c
$ main.exe
c is 0x1234
$ go build -o main.exe
$ main.exe
c is 0x1234

Check the language specifications

So, up to this point, I have dealt with it in my memory. What are the language specifications of each language in the first place?

This time, the language specifications of the processing system (C, Go) actually used Let's see how it is defined to behave when this kind of processing is done.

C

The following is referred to from ISO / IEC 9899 (International standard of C language: C99), shift It is a specification of calculation.

#About the operation of Bit shift
6.5.7 Bitwise shift operators
(Omission)
Semantics
3 The integer promotions are performed on each of the operands. The type of the result is
that of the promoted left operand. If the value of the right operand is negative or is
greater than or equal to the width of the promoted left operand, the behavior is undefined.

(Translated by the author)
If the right operand exceeds the bit width of the "extended" left operand
Also, if the second operand has a negative value, the behavior is undefined.

#About integral promotion
If an int can represent all values of the original type, the value is converted to an int;
otherwise, it is converted to an unsigned int. These are called the integer
promotions.

(Translated by the author)
If int can represent all values of the original type, the value is converted to an int.
Otherwise, it will be converted to an unsigned int. They are"integer promotion" (Integral propaganda)Is called.

The following is the (integer value operation) specification of the shift operation referenced from the Go reference.

Go

Integer overflow
For unsigned integer values, the operations +, -, *, and << are computed modulo 2n,
where n is the bit width of the unsigned integer's type. Loosely speaking,
these unsigned integer operations discard high bits upon overflow, and programs may rely on "wrap around".

(Translated by the author)
(Omission)An unsigned integer operation truncates the high-order bits and "wraps around" if it overflows.
(0xFF for 8-bit integers+ 0x01 =That it will be 0x00)

Again, in shift operations, C is implicitly extended to int, whereas Go has no implicit behavior and clearly defines the behavior.

Summary

Go is sometimes referred to as better C, but as in this example, the actual behavior is not explicit at the syntactic level. In such cases, if the primary documentation is provided in an easy-to-read format, I thought that referring to the language specifications would lead to a quick, reliable, and deeper understanding of the language specifications.

reference open-std.org ISO/IEC 9899:TC3 The Go Programming Language Specification

Recommended Posts

The story of porting code from C to Go and getting hooked (and to the language spec)
A story about porting the code of "Try and understand how Linux works" to Rust
The story of moving from Pipenv to Poetry
Go language to see and remember Part 7 C language in GO language
I tried to illustrate the time and time in C language
The story of copying data from S3 to Google's TeamDrive
After all, the story of returning from Linux to Windows
Go language to see and remember Part 8 Call GO language from Python
The story of Python and the story of NaN
A story about trying to improve the testing process of a system written in C language for 20 years
From the introduction of GoogleCloudPlatform Natural Language API to how to use it
C language to see and remember Part 1 Call C language from Python (hello world)
I tried to extract and illustrate the stage of the story using COTOHA
Try to write python code to generate go code --Try porting JSON-to-Go and so on
C language to see and remember Part 4 Call C language from Python (argument) double
C language to see and remember Part 5 Call C language from Python (argument) Array
The story of trying to reconnect the client
The story of adding MeCab to ubuntu 16.04
Porting and modifying doublet-solver from python2 to python3.
The story of trying deep3d and losing
The story of pep8 changing to pycodestyle
How to make VS Code aware of the venv environment and its benefits
Try porting the "FORTRAN77 Numerical Computing Programming" program to C and Python (Part 1)
[C language] Be careful of the combination of buffering API and non-buffering system call
Try porting the "FORTRAN77 Numerical Computing Programming" program to C and Python (Part 3)
Try porting the "FORTRAN77 Numerical Computing Programming" program to C and Python (Part 2)
C language to see and remember Part 3 Call C language from Python (argument) c = a + b
The story of switching the Azure App Service web system from Windows to Linux
The story of trying Sourcetrail × macOS × VS Code
List of Python code to move and remember
I want to make C ++ code from Python code!
From the introduction of pyethapp to the execution of contract
How to display the modification date of a file in C language up to nanoseconds
The story of Airflow's webserver and DAG, which takes a long time to load
Summary from the beginning to Chapter 1 of the introduction to design patterns learned in the Java language
Extract images and tables from pdf with python to reduce the burden of reporting
The story of switching from WoSign to Let's Encrypt for a free SSL certificate
The and operator of Python's evaluation expression seems to be evaluated from the left side expression
The story of trying to contribute to COVID-19 analysis with AWS free tier and failing
How to limit the API to be published in the C language shared library of Linux
The story of launching a Minecraft server from Discord
The wall of changing the Django service from Python 2.7 to Python 3
The story of Python without increment and decrement operators.
The process of installing Atom and getting Python running
[Updated from time to time] Review of Let Code NumPy
Get the return code of the Python script from bat
Python points from the perspective of a C programmer
[C language] [Linux] Get the value of environment variable
The first step to getting Blender available from Python
I felt that I ported the Python code to C ++ 98.
The story of automatic language conversion of TypeScript / JavaScript / Python
The story of wanting to buy Ring Fit Adventure
The story of using circleci to build manylinux wheels
Now in Singapore The story of creating a LineBot and wanting to do a memorable job
[Linux] [C / C ++] How to get the return address value of a function and the function name of the caller
I want to get rid of import warnings from Pyright and pylint in VS Code
Scraping the member stores of Go To EAT in Osaka Prefecture and converting them to CSV
[Go language] Use OpenWeatherMap and Twitter API to regularly tweet weather information from Raspberry Pi
I considered the machine learning method and its implementation language from the tag information of Qiita