C -安全!
導入
Cはメモリセーフな言語ではなく、それは絶対に正しいです.バッファオーバーのすべての場所、メモリリーク、およびSegDisxもタブーになっていた.この小さな記事では、いくつかの安全なCコードを表示するつもりです、我々は錆でそれを書き直すつもりです.
問題
次のコードを考えます.
// lifetimetest.c
#include <stdio.h>
#include <string.h>
char*
longest(char* a, char* b)
{
if(strlen(a) > strlen(b)){
return a;
}
return b;
}
main(void)
{
char a[] = "Hello";
char b[] = "KosherFoods";
char* res;
res = longest(a, b);
printf("%s", res);
}
ここで関数を定義しますlongest
これは2文字ポインタ(本質的に文字列)をとり、より長い文字列を返す.
このプログラムをコンパイルして実行するならば$ gcc lifetimetest.c -o lft.out && ./lft.out
この出力を取得します.KosherFoods
どちらが期待通りだ
さあ、このプログラムを少し書きましょう
#include <stdio.h>
#include <string.h>
char*
longest(char* a, char* b)
{
if(strlen(a) > strlen(b)){
return a;
}
return b;
}
main(void)
{
char a[] = "Hello";
char* res;
{
char b[] = "KosherFoods";
res = longest(a, b);
}
printf("%s", res);
}
ここで移動b
別のスコープに
このプログラムをコンパイルして実行するならば$ gcc lifetimetest.c -o lft.out && ./lft.out
この出力を取得します.KosherFoods
これまで何も変わったことはない.
もう一度プログラムを書き換えましょう!
#include <stdio.h>
#include <string.h>
char*
longest(char* a, char* b)
{
if(strlen(a) > strlen(b)){
return a;
}
return b;
}
main(void)
{
char a[] = "Hello";
char* res;
{
char b[] = "KosherFoods";
res = longest(a, b);
}
char ohnoo[] = "Plan 9 from User Space";
printf("%s", res);
}
ここでは、2番目のスコープの後に新しい文字列変数を宣言しました
このプログラムをコンパイルして実行するならば$ gcc lifetimetest.c -o lft.out && ./lft.out
この出力を取得します.Plan 9 from User Space
でも……どうやって起こるの?
解説
Cでは、文字列は本質的に文字配列であり、それらの文字列を「保存する」変数は配列の先頭へのポインタだけです.
So longest
文字列のコピーを返しませんが、メモリ内の文字列の先頭へのポインタです.これで心を続けましょう.変数宣言b
内部スコープでは、スコープのメモリに入れられますが、スコープが終了すると、他の変数がメモリに置かれますb
かつては.so res
まだ言いましょう0x000004
どこb
昔は,今は0x000004
はohnoo
文字列.
錆を書き直す
実行に移る前に、いくつかのことを話し合いましょう.さびには「一生」という言葉があります.リファレンスの寿命と、それは参照している参照を妨げます.心でそれを続けましょう.
まず、最長の関数を実装しましょう.
fn longest<'a>(a: &'a str, b: &'a str) -> &'a str {
if a.len() > b.len() {
a
} else {
b
}
}
ヒア'a
は寿命指定子で、これらのパラメータは少なくとも'a
, これで心を続けましょう.
次のコードを考えます.
fn main() {
let a = String::from("APCHIHBALONGERSTRING");
let result: &str;
{
let b = String::from("Banana");
result = longest(a.as_str(), b.as_str());
println!("Longest: {}", result);
}
}
を返します.$ cargo run
次の出力を取得します.
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/lifetime_test`
Longest: APCHIHBALONGERSTRING
あなたがそうすることができるように、さびコンパイラは文句を言いませんでした.
それでは、より高いライフタイムでより低いライフタイムBorrowを使用してみましょう.
fn main() {
let a = String::from("APCHIHBALONGERSTRING");
let result: &str;
{
let b = String::from("Banana");
result = longest(a.as_str(), b.as_str());
}
println!("Longest: {}", result);
}
を返します.cargo run
次の出力を取得します.
Compiling lifetime_test v0.1.0 (/home/ernest/projects/lifetime_test)
error[E0597]: `b` does not live long enough
--> src/main.rs:14:38
|
14 | result = longest(a.as_str(), b.as_str());
| ^^^^^^^^^^ borrowed value does not live long enough
15 | }
| - `b` dropped here while still borrowed
16 | println!("Longest: {}", result);
| ------ borrow later used here
For more information about this error, try `rustc --explain E0597`.
error: could not compile `lifetime_test` due to previous error
これは私たちがリファレンスを借りるからですb
, しかし、後に我々はそれを使用してresult
外側のスコープ(より高い生存期間)で無効です.
結果として、Cで明示的に使用していない限り、Cで同じように未定義の動作を得ることができませんunsafe
キーワード.
結論
この記事では、なぜCが危険でトリッキーに使用されるかの例を示しました.我々は、同じ錆コードの例を提供し、どのように錆はこのような問題を扱う示した.
ノート
私は錆が好きです、そして、私はそれが低レベルのもののようなそれが素晴らしいと思います:オーディオライブラリ、テレビゲームエンジン、ウェブサーバ、その他
Further Reading
次のコードを考えます.
// lifetimetest.c
#include <stdio.h>
#include <string.h>
char*
longest(char* a, char* b)
{
if(strlen(a) > strlen(b)){
return a;
}
return b;
}
main(void)
{
char a[] = "Hello";
char b[] = "KosherFoods";
char* res;
res = longest(a, b);
printf("%s", res);
}
ここで関数を定義しますlongest
これは2文字ポインタ(本質的に文字列)をとり、より長い文字列を返す.このプログラムをコンパイルして実行するならば
$ gcc lifetimetest.c -o lft.out && ./lft.out
この出力を取得します.
KosherFoods
どちらが期待通りださあ、このプログラムを少し書きましょう
#include <stdio.h>
#include <string.h>
char*
longest(char* a, char* b)
{
if(strlen(a) > strlen(b)){
return a;
}
return b;
}
main(void)
{
char a[] = "Hello";
char* res;
{
char b[] = "KosherFoods";
res = longest(a, b);
}
printf("%s", res);
}
ここで移動b
別のスコープにこのプログラムをコンパイルして実行するならば
$ gcc lifetimetest.c -o lft.out && ./lft.out
この出力を取得します.
KosherFoods
これまで何も変わったことはない.もう一度プログラムを書き換えましょう!
#include <stdio.h>
#include <string.h>
char*
longest(char* a, char* b)
{
if(strlen(a) > strlen(b)){
return a;
}
return b;
}
main(void)
{
char a[] = "Hello";
char* res;
{
char b[] = "KosherFoods";
res = longest(a, b);
}
char ohnoo[] = "Plan 9 from User Space";
printf("%s", res);
}
ここでは、2番目のスコープの後に新しい文字列変数を宣言しましたこのプログラムをコンパイルして実行するならば
$ gcc lifetimetest.c -o lft.out && ./lft.out
この出力を取得します.
Plan 9 from User Space
でも……どうやって起こるの?解説
Cでは、文字列は本質的に文字配列であり、それらの文字列を「保存する」変数は配列の先頭へのポインタだけです.
So longest
文字列のコピーを返しませんが、メモリ内の文字列の先頭へのポインタです.これで心を続けましょう.変数宣言b
内部スコープでは、スコープのメモリに入れられますが、スコープが終了すると、他の変数がメモリに置かれますb
かつては.so res
まだ言いましょう0x000004
どこb
昔は,今は0x000004
はohnoo
文字列.
錆を書き直す
実行に移る前に、いくつかのことを話し合いましょう.さびには「一生」という言葉があります.リファレンスの寿命と、それは参照している参照を妨げます.心でそれを続けましょう.
まず、最長の関数を実装しましょう.
fn longest<'a>(a: &'a str, b: &'a str) -> &'a str {
if a.len() > b.len() {
a
} else {
b
}
}
ヒア'a
は寿命指定子で、これらのパラメータは少なくとも'a
, これで心を続けましょう.
次のコードを考えます.
fn main() {
let a = String::from("APCHIHBALONGERSTRING");
let result: &str;
{
let b = String::from("Banana");
result = longest(a.as_str(), b.as_str());
println!("Longest: {}", result);
}
}
を返します.$ cargo run
次の出力を取得します.
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/lifetime_test`
Longest: APCHIHBALONGERSTRING
あなたがそうすることができるように、さびコンパイラは文句を言いませんでした.
それでは、より高いライフタイムでより低いライフタイムBorrowを使用してみましょう.
fn main() {
let a = String::from("APCHIHBALONGERSTRING");
let result: &str;
{
let b = String::from("Banana");
result = longest(a.as_str(), b.as_str());
}
println!("Longest: {}", result);
}
を返します.cargo run
次の出力を取得します.
Compiling lifetime_test v0.1.0 (/home/ernest/projects/lifetime_test)
error[E0597]: `b` does not live long enough
--> src/main.rs:14:38
|
14 | result = longest(a.as_str(), b.as_str());
| ^^^^^^^^^^ borrowed value does not live long enough
15 | }
| - `b` dropped here while still borrowed
16 | println!("Longest: {}", result);
| ------ borrow later used here
For more information about this error, try `rustc --explain E0597`.
error: could not compile `lifetime_test` due to previous error
これは私たちがリファレンスを借りるからですb
, しかし、後に我々はそれを使用してresult
外側のスコープ(より高い生存期間)で無効です.
結果として、Cで明示的に使用していない限り、Cで同じように未定義の動作を得ることができませんunsafe
キーワード.
結論
この記事では、なぜCが危険でトリッキーに使用されるかの例を示しました.我々は、同じ錆コードの例を提供し、どのように錆はこのような問題を扱う示した.
ノート
私は錆が好きです、そして、私はそれが低レベルのもののようなそれが素晴らしいと思います:オーディオライブラリ、テレビゲームエンジン、ウェブサーバ、その他
Further Reading
実行に移る前に、いくつかのことを話し合いましょう.さびには「一生」という言葉があります.リファレンスの寿命と、それは参照している参照を妨げます.心でそれを続けましょう.
まず、最長の関数を実装しましょう.
fn longest<'a>(a: &'a str, b: &'a str) -> &'a str {
if a.len() > b.len() {
a
} else {
b
}
}
ヒア'a
は寿命指定子で、これらのパラメータは少なくとも'a
, これで心を続けましょう.次のコードを考えます.
fn main() {
let a = String::from("APCHIHBALONGERSTRING");
let result: &str;
{
let b = String::from("Banana");
result = longest(a.as_str(), b.as_str());
println!("Longest: {}", result);
}
}
を返します.$ cargo run
次の出力を取得します.Finished dev [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/lifetime_test`
Longest: APCHIHBALONGERSTRING
あなたがそうすることができるように、さびコンパイラは文句を言いませんでした.それでは、より高いライフタイムでより低いライフタイムBorrowを使用してみましょう.
fn main() {
let a = String::from("APCHIHBALONGERSTRING");
let result: &str;
{
let b = String::from("Banana");
result = longest(a.as_str(), b.as_str());
}
println!("Longest: {}", result);
}
を返します.cargo run
次の出力を取得します.Compiling lifetime_test v0.1.0 (/home/ernest/projects/lifetime_test)
error[E0597]: `b` does not live long enough
--> src/main.rs:14:38
|
14 | result = longest(a.as_str(), b.as_str());
| ^^^^^^^^^^ borrowed value does not live long enough
15 | }
| - `b` dropped here while still borrowed
16 | println!("Longest: {}", result);
| ------ borrow later used here
For more information about this error, try `rustc --explain E0597`.
error: could not compile `lifetime_test` due to previous error
これは私たちがリファレンスを借りるからですb
, しかし、後に我々はそれを使用してresult
外側のスコープ(より高い生存期間)で無効です.結果として、Cで明示的に使用していない限り、Cで同じように未定義の動作を得ることができません
unsafe
キーワード.結論
この記事では、なぜCが危険でトリッキーに使用されるかの例を示しました.我々は、同じ錆コードの例を提供し、どのように錆はこのような問題を扱う示した.
ノート
私は錆が好きです、そして、私はそれが低レベルのもののようなそれが素晴らしいと思います:オーディオライブラリ、テレビゲームエンジン、ウェブサーバ、その他
Further Reading
Reference
この問題について(C -安全!), 我々は、より多くの情報をここで見つけました https://dev.to/ernestvonmoscow/c-unsafe-1kh2テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol