0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

7.3 Complex arithmetic <complex.h>, CN3054:2022 (15) p197.c

Last updated at Posted at 2022-11-20

はじめに(Introduction)

N3054 Working Draft, Standard for Programming Language C

C++ nは、ISO/IEC JTC1 SC22 WG14の作業原案(Working Draft)です。
公式のISO/IEC 9899原本ではありません。

ISO/IEC JTC1 SC22 のWG14を含むいくつかのWGでは、可能な限り作業文書を公開し、幅広い意見を求めています。

ISO/IEC JTC1 SC7からISO/IEC JTC1 SC22リエゾンとして、2000年頃、C/C++の品質向上に貢献しようとした活動をしていたことがあります。その頃は、まだISO/IEC TS 17961の原案が出る前です。Cの精神が優勢で、セキュリティ対策は補助的な位置付けでした。ISO/IEC TS 17961の制定と、C/C++のライブラリ類の見直しと、C++の進化はどんどん進んでいきます。 

進化の具合が、どちらに行こうとしているかは、コンパイルて実行させてみないとわかりません。C/C++の規格案の電子ファイルは、そのままコンパイルできる形式であるとよいと主張してきました。MISRA-C/C++, CERTC/C++でも同様です。MISRA-C/C++は、Example Suiteという形で、コード断片をコンパイルできる形で提供するようになりました。

一連の記事はコード断片をコンパイルできる形にする方法を検討してコンパイル、リンク、実行して、規格案の原文と処理系(gcc, clang)との違いを確認し、技術内容を検討し、ISO/IEC JTC1 SC22 WG21にフィードバックするために用います。
また、CERT C/C++, MISRA C/C++等のコーディング標準のコード断片をコンパイルする際の参考にさせていただこうと考えています。CERT C++, MISRA C++が標準化の動きとの時間的なずれがあれば確認できれば幸いです。また、boostライブラリとの関連、Linux OS, 箱庭プロジェクト、g++(GCC), clang++(LLVM)との関係も調査中です。
何か、抜け漏れ、耳より情報がありましたらおしらせくださると幸いです。

最新規格はCN3096

<この項は書きかけです。順次追記します。>

背景(back ground)

C/C++でコンパイルエラーが出ると、途方にくれることがしばしばあります。
何回かに1回は、該当するエラーが検索できます。
ただ、条件が違っていて、そこでの修正方法では目的を達成しないこともしばしばです。いろいろな条件のコンパイルエラーとその対応方法について、広く記録することによって、いつか同じエラーに遭遇した時にやくに立つことを目指しています。

過去に何度か、自分のネットでの記録に助けられたことがあります。

また
https://researchmap.jp/joub9b3my-1797580/#_1797580
に記載したサイトのお世話になっています。

作業方針(sequence)

clangでは--std=c11, -std=C17 -std=c2xの3種類
gccでは-std=c11, -std=C17 -std=c2xの3種類
でコンパイルし、

1)コンパイルエラーを収集する。
2)コンパイルエラーをなくす方法を検討する。
コンパイルエラーになる例を示すだけが目的のコードは、コンパイルエラーをなくすのではなく、コンパイルエラーの種類を収集するだけにする。
文法を示すのが目的のコード場合に、コンパイルエラーをなくすのに手間がかかる場合は、順次作業します。
3)リンクエラーをなくす方法を検討する。
文法を示すのが目的のコード場合に、リンクエラーをなくすのに手間がかかる場合は、順次作業します。
4)意味のある出力を作る。
コンパイル、リンクが通っても、意味のある出力を示そうとすると、コンパイル・リンクエラーが出て収拾できそうにない場合がある。順次作業します。

1)だけのものから4)まで進んだものと色々ある状態です。一歩でも前に進むご助言をお待ちしています。「検討事項」の欄に現状を記録するようにしています。

bash
$ docker run -v /Users/ogawakiyoshi/n4910/n3540:/Users/ogawakiyoshi/n4910/n3540 -it kaizenjapan/n3540 /bin/bash

読書感想文

CコンパイラによるC言語規格の読書感想文として掲載しています。

コンパイル実験が、CN3242に対する、gccとclangによる感想文だということご理解いただけると幸いです。

読書感想文は人間かAIだけが作るものとは限りません。
本(電子書籍を含む)を入力として、その内容に対する文字列を読書感想文として受け止めましょう。
元の文章をあり方、コンパイルできるように電子化しておくこと、コンパイラが解釈可能な断片の作り方など。

個人開発

Cコンパイラの試験を一人でもくもくとやっているのは個人開発の一つの姿です。

<この項は書きかけです。順次追記します。>

編纂器(Compiler)

clang --version

Debian clang version 14.0.6-++20220622053050+f28c006a5895-1~exp1~20220622173135.152
Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/bin

gcc --version

gcc (GCC) 12.1.0 Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

7.3 Complex arithmetic , CN3054:2022 (15) p197.c

算譜(source code)

p197.c
// CN3054 Committee Draft, Standard for Programming Language C
// http://www.open-std.org/jtc1/sc22/wg14/docs/papers/2022/n3054.pdf
const char * n3054 = "7.3 Complex arithmetic <complex.h>, CN3054:2022 (15) p197.c";
// Debian clang version 14.0.5-++20220610033153+c12386ae247c-
// g++ (GCC) 12.1.0 Copyright (C) 2022 Free Software Foundation, Inc.
// Edited by Dr. OGAWA Kiyoshi. Compile procedure and results record.
// C++N3054:2022 Standard Working Draft on ISO/IEC 14882(0) sample code compile list

#include "N3054.h"

// 7.3.4 The CX_LIMITED_RANGE pragma Synopsis
// The usual mathematical formulas for complex multiply, divide, and absolute value are problem- atic because of their treatment of infinities and because of undue overflow and underflow. The CX_LIMITED_RANGE pragma can be used to inform the implementation that (where the state is "on") the usual mathematical formulas are acceptable.245) The pragma can occur either outside external declarations or preceding all explicit declarations and statements inside a compound statement. When outside external declarations, the pragma takes effect from its occurrence until another CX_LIMITED_RANGE pragma is encountered, or until the end of the translation unit. When inside a compound statement, the pragma takes effect from its occurrence until another CX_LIMITED_RANGE pragma is encountered (including within a nested compound statement), or until the end of the compound statement; at the end of a compound statement the state for the pragma is restored to its condition just before the compound statement. If this pragma is used in any other context, the behavior is undefined. The default state for the pragma is "off".
// 7.3.5 Trigonometric functions
// 7.3.5.1 The cacos functions Synopsis
//  The cacos functions compute the complex arc cosine of z, with branch cuts outside the interval [−1, +1] along the real axis.
// 245)The purpose of the pragma is to allow the implementation to use the formulas:(x+iy)×(u+iv) = (xu−yv)+i(yu+xv) (x+iy)/(u+iv) = [(xu+yv)+i(yu−xv)]/(u2 +v2) |x+iy| = 􏰀x2 +y2
// where the programmer can determine they are safe.
//          Description
#include <complex.h>
#pragma STDC CX_LIMITED_RANGE on-off-switch
#include <complex.h>
double complex cacos(double complex z);
float complex cacosf(float complex z);
long double complex cacosl(long double complex z);
// Description
//  Returns
//  The cacos functions return the complex arc cosine value, in the range of a strip mathematically unbounded along the imaginary axis and in the interval [0, π] along the real axis.
//  7.3.5.2 The casin functions
// Synopsis
//  The casin functions compute the complex arc sine of z, with branch cuts outside the interval [−1, +1] along the real axis.
// Returns
//  The casin functions return the complex arc sine value, in the range of a strip mathematically unbounded along the imaginary axis and in the interval [− π , + π ] along the real axis.
#include <complex.h>
double complex casin(double complex z);
float complex casinf(float complex z);
long double complex casinl(long double complex z);
//                 Description
//   7.3.5.3 The catan functions Synopsis
#include <complex.h>
double complex catan(double complex z);
float complex catanf(float complex z);
long double complex catanl(long double complex z);
//                 Description
//  The catan functions compute the complex arc tangent of z, with branch cuts outside the interval [−i, +i] along the imaginary axis.
// Returns
//  The catan functions return the complex arc tangent value, in the range of a strip mathematically unbounded along the imaginary axis and in the interval [− π , + π ] along the real axis. 22
// 7.3.5.4 The ccos functions
// Synopsis
//  The ccos functions compute the complex cosine of z. Returns
//  The ccos functions return the complex cosine value.
// 7.3.5.5 The csin functions
// Synopsis
// The csin functions compute the complex sine of z.
#include <complex.h>
double complex ccos(double complex z);
float complex ccosf(float complex z);
long double complex ccosl(long double complex z);
//                 Description
#include <complex.h>
double complex csin(double complex z);
float complex csinf(float complex z);
long double complex csinl(long double complex z);
//                 Description
// Returns
//  The csin functions return the complex sine value. 7.3.5.6 The ctan functions
// Synopsis
//  The ctan functions compute the complex tangent of z. Returns
//  The ctan functions return the complex tangent value.
// 7.3.6 Hyperbolic functions
// 7.3.6.1 The cacosh functions Synopsis
//  The cacosh functions compute the complex arc hyperbolic cosine of z, with a branch cut at values less than 1 along the real axis.
// Returns
//  The cacosh functions return the complex arc hyperbolic cosine value, in the range of a half-strip of nonnegative values along the real axis and in the interval [−iπ, +iπ] along the imaginary axis.
// 7.3.6.2 The casinh functions Synopsis
//  The casinh functions compute the complex arc hyperbolic sine of z, with branch cuts outside the interval [−i, +i] along the imaginary axis.
// Returns
//  The casinh functions return the complex arc hyperbolic sine value, in the range of a strip mathe- matically unbounded along the real axis and in the interval [− iπ , + iπ ] along the imaginary axis. 22
// 7.3.6.3 The catanh functions Synopsis
#include <complex.h>
double complex ctan(double complex z);
float complex ctanf(float complex z);
long double complex ctanl(long double complex z);
//             Description
#include <complex.h>
double complex cacosh(double complex z);
float complex cacoshf(float complex z);
long double complex cacoshl(long double complex z);
//              Description
#include <complex.h>
double complex casinh(double complex z);
float complex casinhf(float complex z);
long double complex casinhl(long double complex z);
//              Description
#include <complex.h>
double complex catanh(double complex z);
float complex catanhf(float complex z);
long double complex catanhl(long double complex z);
// Description
//  The catanh functions compute the complex arc hyperbolic tangent of z, with branch cuts outside the interval [−1, +1] along the real axis.
// Returns
//  The catanh functions return the complex arc hyperbolic tangent value, in the range of a strip mathematically unbounded along the real axis and in the interval [− iπ , + iπ ] along the imaginary 22 axis.
// 7.3.6.4 The ccosh functions Synopsis
//  The ccosh functions compute the complex hyperbolic cosine of z. // Returns
//  The ccosh functions return the complex hyperbolic cosine value.
// 7.3.6.5 The csinh functions
// Synopsis
//  The csinh functions compute the complex hyperbolic sine of z. // Returns
// The csinh functions return the complex hyperbolic sine value.
// 7.3.6.6 The ctanh functions
// Synopsis
//  The ctanh functions compute the complex hyperbolic tangent of z. // Returns
//  The ctanh functions return the complex hyperbolic tangent value.
// 7.3.7 Exponential and logarithmic functions 7.3.7.1 The cexp functions
// Synopsis
#include <complex.h>
double complex ccosh(double complex z);
float complex ccoshf(float complex z);
long double complex ccoshl(long double complex z);
//                Description
#include <complex.h>
double complex csinh(double complex z);
float complex csinhf(float complex z);
long double complex csinhl(long double complex z);
//                Description
#include <complex.h>
double complex ctanh(double complex z);
float complex ctanhf(float complex z);
long double complex ctanhl(long double complex z);
//                 Description
#include <complex.h>
double complex cexp(double complex z);
float complex cexpf(float complex z);
long double complex cexpl(long double complex z);
// Description
//  The cexp functions compute the complex base-e exponential of z. // Returns
//  The cexp functions return the complex base-e exponential value.
// 7.3.7.2 The clog functions
// Synopsis
//  The clog functions compute the complex natural (base-e) logarithm of z, with a branch cut along the negative real axis.
// Returns
//  The clog functions return the complex natural logarithm value, in the range of a strip mathematically unbounded along the real axis and in the interval [−iπ, +iπ] along the imaginary axis.
// 7.3.8 Power and absolute-value functions
// 7.3.8.1 The cabs functions
// Synopsis
//  The cabs functions compute the complex absolute value (also called norm, modulus, or magnitude) of z.
// Returns
//  The cabs functions return the complex absolute value.
// 7.3.8.2 The cpow functions
// Synopsis
//  The cpow functions compute the complex power function xy, with a branch cut for the first parameter along the negative real axis.
// Returns
// The cpow functions return the complex power function value.
#include <complex.h>
double complex clog(double complex z);
float complex clogf(float complex z);
long double complex clogl(long double complex z);
//              Description
#include <complex.h>
double cabs(double complex z);
float cabsf(float complex z);
long double cabsl(long double complex z);
//              Description
#include <complex.h>
double complex cpow(double complex x, double complex y);
float complex cpowf(float complex x, float complex y);
long double complex cpowl(long double complex x, long double complex y);
//              Description
// 7.3.8.3 The csqrt functions
// Synopsis
//  The csqrt functions compute the complex square root of z, with a branch cut along the negative real axis.
// Returns
//  The csqrt functions return the complex square root value, in the range of the right half-plane (including the imaginary axis).
// 7.3.9 Manipulation functions
// 7.3.9.1 The carg functions Synopsis
//  The carg functions compute the argument (also called phase (which is an angle)) of z, with a branch cut along the negative real axis.
// Returns
//  The carg functions return the value of the argument in the interval [−π, +π].
// 7.3.9.2 The cimag functions
// Synopsis
//  The cimag functions compute the imaginary part of z.246) Returns
//  The cimag functions return the imaginary part value (as a real).
// 7.3.9.3 The CMPLX macros
// Synopsis
#include <complex.h>
double complex csqrt(double complex z);
float complex csqrtf(float complex z);
long double complex csqrtl(long double complex z);
//                 Description
#include <complex.h>
double carg(double complex z);
float cargf(float complex z);
long double cargl(long double complex z);
//                 Description
#include <complex.h>
double cimag(double complex z);
float cimagf(float complex z);
long double cimagl(long double complex z);
//                 Description
#include <complex.h>
double complex CMPLX(double x, double y);
float complex CMPLXF(float x, float y);
long double complex CMPLXL(long double x, long double y);
// 246)Foravariablezofcomplextype,z == creal(z)+cimag(z)*I.
// Description
//  The CMPLX macros expand to an expression of the specified complex type, with the real part having the (converted) value of x and the imaginary part having the (converted) value of y. The resulting expression shall be suitable for use as an initializer for an object with static or thread storage duration, provided both arguments are likewise suitable.
// Returns
//  The CMPLX macros return the complex value x + iy.
//  NOTE 1 These macros act as if the implementation supported imaginary types and the definitions were:
// 7.3.9.4 The conj functions Synopsis
//  The conj functions compute the complex conjugate of z, by negating the sign of its imaginary part. Returns
//  The conj functions return the complex conjugate value.
// 7.3.9.5 The cproj functions
// Synopsis
//  The cproj functions compute a projection of z onto the Riemann sphere where z projects to z except that all complex infinities (even those with one infinite part and one NaN part) project to positive infinity on the real axis. If z has an infinite part, then cproj(z) is equivalent to INFINITY + I * copysign(0.0, cimag(z))
// Returns
//  The cproj functions return the value of the projection onto the Riemann sphere.
// 7.3.9.6 The creal functions
// Synopsis
#define CMPLX(x, y) ((double complex)((double)(x) + \ _Imaginary_I * (double)(y)))
#define CMPLXF(x, y) ((float complex)((float)(x) + \ _Imaginary_I * (float)(y)))
#define CMPLXL(x, y) ((long double complex)((long double)(x) + \ _Imaginary_I * (long double)(y)))
#include <complex.h>
double complex conj(double complex z);
float complex conjf(float complex z);
long double complex conjl(long double complex z);
//  Description
#include <complex.h>
double complex cproj(double complex z);
float complex cprojf(float complex z);
long double complex cprojl(long double complex z);
//  Description
#include <complex.h>
double creal(double complex z);
float crealf(float complex z);
long double creall(long double complex z);
// Description
//  The creal functions compute the real part of z.247) Returns
//  The creal functions return the real part value.
//  247)Foravariablezofcomplextype,z == creal(z)+cimag(z)*I.
int main() {
//    PR3(st.a,st.b,st.c,d);
    printf("%s\n", n3054);
    return EXIT_SUCCESS;
}

編纂・実行結果(compile and go)

bash
$ clang p197.c -std=11 -o p197l -I. -Wall
p197.c:20:31: warning: expected 'ON' or 'OFF' or 'DEFAULT' in pragma [-Wunknown-pragmas]
#pragma STDC CX_LIMITED_RANGE on-off-switch        
                              ^
1 warning generated.
7.3 Complex arithmetic <complex.h>, CN3054:2022 (15) p197.c

$ clang p197.c -std=17 -o p197l -I. -Wall
p197.c:20:31: warning: expected 'ON' or 'OFF' or 'DEFAULT' in pragma [-Wunknown-pragmas]
#pragma STDC CX_LIMITED_RANGE on-off-switch        
                              ^
1 warning generated.
7.3 Complex arithmetic <complex.h>, CN3054:2022 (15) p197.c

$ clang p197.c -std=2x -o p197l -I. -Wall
p197.c:20:31: warning: expected 'ON' or 'OFF' or 'DEFAULT' in pragma [-Wunknown-pragmas]
#pragma STDC CX_LIMITED_RANGE on-off-switch        
                              ^
1 warning generated.
7.3 Complex arithmetic <complex.h>, CN3054:2022 (15) p197.c

$ gcc p197.c -std=11 -o p197g -I. -Wall
p197.c:20: warning: ignoring '#pragma STDC CX_LIMITED_RANGE' [-Wunknown-pragmas]
   20 | #pragma STDC CX_LIMITED_RANGE on-off-switch
      | 
In file included from p197.c:19:
p197.c:200:16: error: expected identifier or '(' before '__builtin_complex'
  200 | double complex CMPLX(double x, double y);
      |                ^~~~~
p197.c:201:15: error: expected identifier or '(' before '__builtin_complex'
  201 | float complex CMPLXF(float x, float y);
      |               ^~~~~~
p197.c:202:21: error: expected identifier or '(' before '__builtin_complex'
  202 | long double complex CMPLXL(long double x, long double y);
      |                     ^~~~~~
p197.c:219: warning: "CMPLX" redefined
  219 | #define CMPLX(x, y) ((double complex)((double)(x) + \ _Imaginary_I * (double)(y)))
      | 
/usr/include/complex.h:57: note: this is the location of the previous definition
   57 | # define CMPLX(x, y) __builtin_complex ((double) (x), (double) (y))
      | 
p197.c:220: warning: "CMPLXF" redefined
  220 | #define CMPLXF(x, y) ((float complex)((float)(x) + \ _Imaginary_I * (float)(y)))
      | 
/usr/include/complex.h:58: note: this is the location of the previous definition
   58 | # define CMPLXF(x, y) __builtin_complex ((float) (x), (float) (y))
      | 
p197.c:221: warning: "CMPLXL" redefined
  221 | #define CMPLXL(x, y) ((long double complex)((long double)(x) + \ _Imaginary_I * (long double)(y)))
      | 
/usr/include/complex.h:59: note: this is the location of the previous definition
   59 | # define CMPLXL(x, y) __builtin_complex ((long double) (x), (long double) (y))
      | 

$ gcc p197.c -std=c17 -o p197g -I. -Wall
p197.c:20: warning: ignoring '#pragma STDC CX_LIMITED_RANGE' [-Wunknown-pragmas]
   20 | #pragma STDC CX_LIMITED_RANGE on-off-switch
      | 
In file included from p197.c:19:
p197.c:200:16: error: expected identifier or '(' before '__builtin_complex'
  200 | double complex CMPLX(double x, double y);
      |                ^~~~~
p197.c:201:15: error: expected identifier or '(' before '__builtin_complex'
  201 | float complex CMPLXF(float x, float y);
      |               ^~~~~~
p197.c:202:21: error: expected identifier or '(' before '__builtin_complex'
  202 | long double complex CMPLXL(long double x, long double y);
      |                     ^~~~~~
p197.c:219: warning: "CMPLX" redefined
  219 | #define CMPLX(x, y) ((double complex)((double)(x) + \ _Imaginary_I * (double)(y)))
      | 
/usr/include/complex.h:57: note: this is the location of the previous definition
   57 | # define CMPLX(x, y) __builtin_complex ((double) (x), (double) (y))
      | 
p197.c:220: warning: "CMPLXF" redefined
  220 | #define CMPLXF(x, y) ((float complex)((float)(x) + \ _Imaginary_I * (float)(y)))
      | 
/usr/include/complex.h:58: note: this is the location of the previous definition
   58 | # define CMPLXF(x, y) __builtin_complex ((float) (x), (float) (y))
      | 
p197.c:221: warning: "CMPLXL" redefined
  221 | #define CMPLXL(x, y) ((long double complex)((long double)(x) + \ _Imaginary_I * (long double)(y)))
      | 
/usr/include/complex.h:59: note: this is the location of the previous definition
   59 | # define CMPLXL(x, y) __builtin_complex ((long double) (x), (long double) (y))
      | 

$ gcc p197.c -std=c2x -o p197g -I. -Wall
p197.c:20: warning: ignoring '#pragma STDC CX_LIMITED_RANGE' [-Wunknown-pragmas]
   20 | #pragma STDC CX_LIMITED_RANGE on-off-switch
      | 
In file included from p197.c:19:
p197.c:200:16: error: expected identifier or '(' before '__builtin_complex'
  200 | double complex CMPLX(double x, double y);
      |                ^~~~~
p197.c:201:15: error: expected identifier or '(' before '__builtin_complex'
  201 | float complex CMPLXF(float x, float y);
      |               ^~~~~~
p197.c:202:21: error: expected identifier or '(' before '__builtin_complex'
  202 | long double complex CMPLXL(long double x, long double y);
      |                     ^~~~~~
p197.c:219: warning: "CMPLX" redefined
  219 | #define CMPLX(x, y) ((double complex)((double)(x) + \ _Imaginary_I * (double)(y)))
      | 
/usr/include/complex.h:57: note: this is the location of the previous definition
   57 | # define CMPLX(x, y) __builtin_complex ((double) (x), (double) (y))
      | 
p197.c:220: warning: "CMPLXF" redefined
  220 | #define CMPLXF(x, y) ((float complex)((float)(x) + \ _Imaginary_I * (float)(y)))
      | 
/usr/include/complex.h:58: note: this is the location of the previous definition
   58 | # define CMPLXF(x, y) __builtin_complex ((float) (x), (float) (y))
      | 
p197.c:221: warning: "CMPLXL" redefined
  221 | #define CMPLXL(x, y) ((long double complex)((long double)(x) + \ _Imaginary_I * (long double)(y)))
      | 
/usr/include/complex.h:59: note: this is the location of the previous definition
   59 | # define CMPLXL(x, y) __builtin_complex ((long double) (x), (long double) (y))
      | 

検討事項(agenda)

clang++はコンパイルエラーなし。g++はコンパイルエラー。

応用例1 MISRA C/C++

MISRA C まとめ #include

MISRA C++ 5-0-16

応用例2 CERT C/C++

SEI CERT C++ Coding Standard AA. Bibliography 確認中。

MISRA C/C++, AUTOSAR C++, CERT C/C++とC/C++工業標準をコンパイルする

自己参考資料(self reference)

関連する自己参照以外は、こちらの先頭に移転。

C言語(C++)に対する誤解、曲解、無理解、爽快。

C2011コンパイル一覧@researchmap

https://researchmap.jp/jownvh0ye-1797580/#_1797580

[C][C++]の国際規格案の例題をコンパイルするときの課題7つ。

C Puzzle Bookの有り難み5つ、C言語規格及びCコンパイラの特性を認識

dockerにclang

docker gnu(gcc/g++) and llvm(clang/clang++)

コンパイル用shell script C版(clangとgcc)とC++版(clang++とg++)

astyle 使ってみた

<この記事は個人の過去の経験に基づく個人の感想です。現在所属する組織、業務とは関係がありません。>

文書履歴(document history)

ver. 0.01 初稿  20221120
ver. 0.02 ありがとう追記 20230622

最後までおよみいただきありがとうございました。

いいね 💚、フォローをお願いします。

Thank you very much for reading to the last sentence.

Please press the like icon 💚 and follow me for your happy life.

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?