javacommons
@javacommons

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

(AIが)作ったZIG言語プログラムが動かない人集まれ!

解決したいこと

AIが作ったZIG言語プログラムのコンパイルを通す


【例】

zig言語でテキストをファイルに書き込むプログラムを書いて

const std = @import("std");

pub fn main() !void {
    var file = try std.fs.cwd().createFile("output.txt");
    defer file.close();

    try file.writeAll("Hello, world!");
}
run.sh
#! /usr/bin/env bash
set -uvx
set -e
zig version
zig run main.zig

run.sh を実行すると

~/zig/2023-0913-2048>bash run.sh
set -e
+ set -e
zig version
+ zig version
0.11.0
zig run main.zig
+ zig run main.zig
main.zig:4:32: error: member function expected 2 argument(s), found 1
    var file = try std.fs.cwd().createFile("output.txt");
                   ~~~~~~~~~~~~^~~~~~~~~~~
C:\Users\user\scoop\apps\zig\current\lib\std\fs.zig:1283:9: note: function declared here
    pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
    ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
referenced by:
    callMain: C:\Users\user\scoop\apps\zig\current\lib\std\start.zig:574:32
    initEventLoopAndCallMain: C:\Users\user\scoop\apps\zig\current\lib\std\start.zig:508:34
    remaining reference traces hidden; use '-freference-trace' to see all reference traces
exit status 1
~/zig/2023-0913-2048>

このような動かせないZIG言語プログラムを最新版のZIGコンパイラで動くように手直しするプロジェクトです。
自作やAIが作成したサンプルコードをお寄せください。また、動くように手直ししたコードサンプルも募集します。

1

zig言語でテキストをファイルに書き込むプログラムを書いて

zig 0.11.0 では std.fs.cwd().createFile() に第二引数として「flags: File.CreateFlags」が追加されています。flags: File.CreateFlags は構造体ですが、すべてデフォルトのメンバを指定することにして「.{}」を指定しています。

const std = @import("std");

pub fn main() !void {
    var file = try std.fs.cwd().createFile("output.txt", .{});
    defer file.close();

    try file.writeAll("Hello, world!");
}
~/zig/2023-0913-2048>bash run.sh
set -e
+ set -e
zig version
+ zig version
0.11.0
zig run main.zig
+ zig run main.zig
~/zig/2023-0913-2048>ls -ltr
-rwxa--  71 Sep 13 20:49:13 run.sh*
-rwxa-- 189 Sep 13 20:56:06 main.zig*
-rwxa--  13 Sep 13 20:56:15 output.txt*
~/zig/2023-0913-2048>

これで動作しました。zig 0.11.0 以降になって動作しなくなったら教えてください。
再度修正します。

0Like

ZIG言語で一秒ごとに時刻を表示するプログラムを書いて

このコードはAIに尋ねた上で取り合えず、動くようにしたコードです。(挫折版)

const std = @import("std");

pub fn main() !void {
    while (true) {
        // 現在時刻を取得
        const now = std.time.nanoTimestamp();
        // 時刻を文字列に変換
        const formatted = std.fmt.fmtDurationSigned(@truncate(now));
        // 標準出力に表示
        std.debug.print("{}\n", .{formatted});
        // 一秒待機
        std.time.sleep(1 * std.time.ns_per_s);
    }
}
run.sh
#! /usr/bin/env bash
set -uvx
set -e
zig version
zig run main.zig
~/zig/timer>bash run.sh
set -e
+ set -e
zig version
+ zig version
0.11.0
zig run main.zig
+ zig run main.zig
53y38w2d12h7m34.386s
53y38w2d12h7m35.401s
53y38w2d12h7m36.41s
53y38w2d12h7m37.423s
53y38w2d12h7m38.434s
53y38w2d12h7m39.439s
53y38w2d12h7m40.441s

時刻の代わりに、1970年1月1日午前0時0分0秒からの秒数(UNIX時間)を drutation として表示しています。「時刻を文字列に変換」を行うのに適当なAPIが 0.11.0 で見つからなかったためです。また、時刻が表示できるならナノ秒単位でなくていかまいません。理想はミリ秒ですが秒でもOKとします。

0Like

ZIG言語で一秒ごとに時刻を表示するプログラムを書いて

C++との連携で実現してみました。

run.sh
#! /usr/bin/env bash
set -uvx
set -e
zig version
zig c++ -c time2str.cpp
zig build-exe -I. main.zig time2str.obj -lc -lc++
./main.exe
main.zig
const std = @import("std");
const time2str = @cImport({
    @cInclude("time2str.h");
});

pub fn main() !void {
    while (true) {
        // 現在時刻を取得
        const now = std.time.timestamp(); // 秒数
        // 時刻を文字列に変換
        const formatted = time2str.time2str(now);
        // 標準出力に表示
        std.debug.print("{s}\n", .{formatted});
        // 一秒待機
        std.time.sleep(1 * std.time.ns_per_s);
    }
}
time2str.h
#pragma once

#include "stdint.h"

#ifdef __cplusplus
extern "C" {
#endif

const char *time2str(int64_t t);

#ifdef __cplusplus
}
#endif
time2str.cpp
#include "time2str.h"
#include "time.h"
#include <ctime>
#include <string>

static std::string& leftTrim(std::string& str, std::string& chars)
{
    str.erase(0, str.find_first_not_of(chars));
    return str;
}

static std::string& rightTrim(std::string& str, std::string& chars)
{
    str.erase(str.find_last_not_of(chars) + 1);
    return str;
}

static std::string& trimString(std::string& str, std::string& chars)
{
    return leftTrim(rightTrim(str, chars), chars);
}
const char *time2str(int64_t t)
{
    static thread_local std::string result;
    static std::string chars_to_trim = " \t\r\n";
    time_t tt = t;
    result = std::asctime(std::localtime(&tt));
    trimString(result, chars_to_trim);
    return result.c_str();
}
実行結果
set -e
+ set -e
zig version
+ zig version
0.11.0
zig c++ -c time2str.cpp
+ zig c++ -c time2str.cpp
zig build-exe -I. main.zig time2str.obj -lc -lc++
+ zig build-exe -I. main.zig time2str.obj -lc -lc++
./main.exe
+ ./main.exe
Wed Sep 13 22:33:56 2023
Wed Sep 13 22:33:57 2023
Wed Sep 13 22:33:58 2023
Wed Sep 13 22:33:59 2023
Wed Sep 13 22:34:00 2023
Wed Sep 13 22:34:01 2023
Wed Sep 13 22:34:02 2023
Wed Sep 13 22:34:03 2023
Wed Sep 13 22:34:05 2023
Wed Sep 13 22:34:06 2023
Wed Sep 13 22:34:07 2023
Wed Sep 13 22:34:08 2023
Wed Sep 13 22:34:09 2023
Wed Sep 13 22:34:10 2023
Wed Sep 13 22:34:11 2023
Wed Sep 13 22:34:12 2023
Wed Sep 13 22:34:13 2023
1Like

@aktokaji さん、ありがとうございます。

ZIG言語で一秒ごとに時刻を表示するプログラムを書いて

C++との連携で実現してみました。

やはり秒単位になりますか。ベンチマーク等に使うためにミリ秒程度の精度が出せたら理想的なんですが・・・。
でも、時刻が表示できるようになって前進です!投稿ありがとうございました。

1Like

c++でミリ秒単位で現在時刻を表示するには
https://www.perplexity.ai/search/9d046529-a1df-4a31-955d-e07a7f9e6bce?s=c

#include <iostream>
#include <chrono>
#include <ctime>
#include <iomanip>

int main() {
    auto now = std::chrono::system_clock::now();
    auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
    auto value = now_ms.time_since_epoch();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(value);
    auto millis = duration.count() % 1000;

    std::time_t now_c = std::chrono::system_clock::to_time_t(now_ms);
    std::tm* now_tm = std::localtime(&now_c);

    char buffer[80];
    std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", now_tm);
    std::cout << buffer << "." << std::setfill('0') << std::setw(3) << millis << std::endl;

    return 0;
}

これを参考にミリ秒単位での時刻表示に挑戦してみたいと思います。

0Like

ZIG言語で一秒ごとに時刻を表示するプログラムを書いて

run.sh
#! /usr/bin/env bash
set -uvx
set -e
zig version
zig c++ -c -I. time2str.cpp
zig build-exe -I. main.zig time2str.obj -lc -lc++
./main.exe
main.zig
const std = @import("std");
const time2str = @cImport({
    @cInclude("time2str.h");
});

pub fn main() !void {
    while (true) {
        // 現在時刻を取得
        const now = std.time.milliTimestamp(); // ミリ秒
        // 時刻を文字列に変換
        const formatted = time2str.time2str(now);
        // 標準出力に表示
        std.debug.print("{s}\n", .{formatted});
        // 一秒待機
        std.time.sleep(1 * std.time.ns_per_s);
    }
}
time2str.h
#pragma once

#include "stdint.h"

#ifdef __cplusplus
extern "C" {
#endif

const char *time2str(int64_t t);

#ifdef __cplusplus
}
#endif
time2str.cpp
#include "time2str.h"
#include <string>
#include <chrono>
#include <ctime>
#include <iomanip>
#include <sstream>

const char *time2str(int64_t t)
{
    static thread_local std::string result;
    std::time_t now_c = t / 1000;
    std::tm* now_tm = std::localtime(&now_c);
    char buffer[80];
    std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", now_tm);
    std::stringstream ss;
    int64_t millis = t % 1000;
    ss << buffer << "." << std::setfill('0') << std::setw(3) << millis;
    result = ss.str();
    return result.c_str();
}
実行結果
~/zig/timer3>bash run.sh
set -e
+ set -e
zig version
+ zig version
0.11.0
zig c++ -c -I. time2str.cpp
+ zig c++ -c -I. time2str.cpp
zig build-exe -I. main.zig time2str.obj -lc -lc++
+ zig build-exe -I. main.zig time2str.obj -lc -lc++
./main.exe
+ ./main.exe
2023-09-14 08:07:03.998
2023-09-14 08:07:05.003
2023-09-14 08:07:06.019
2023-09-14 08:07:07.033
2023-09-14 08:07:08.034
2023-09-14 08:07:09.044
2023-09-14 08:07:10.059
2023-09-14 08:07:11.071
2023-09-14 08:07:12.075
2023-09-14 08:07:13.088

時刻のミリ秒まで表示できました。

1Like

zig言語で https://raw.githubusercontent.com/ScoopInstaller/Main/master/bucket/7zip.json にアクセスして、テキストを読み取り JSON 変数 json に格納した上で、json.architecture["64bit"].url の文字列を取得するには

main.zig(zig 0.11.0 で動かない)
const std = @import("std");
const http = std.net.http.client;
const allocator = std.heap.page_allocator;
const json = std.json;

pub fn main() !void {
    var client = http.Client.init(allocator);
    defer client.deinit();
    const url = "https://raw.githubusercontent.com/ScoopInstaller/Main/master/bucket/7zip.json";
    const request = try http.Request.init("GET", url);
    const response = try client.fetch(request);
    const body = try response.getBody();
    const decoded = try json.parse(body);
    const architecture = try decoded.architecture.get("64bit");
    const url2 = try architecture.url.string();
    std.debug.print("url: {}\n", .{url2});
}
0Like

zig言語で https://raw.githubusercontent.com/ScoopInstaller/Main/master/bucket/7zip.json にアクセスして、テキストを読み取り JSON 変数 json に格納した上で、json.architecture["64bit"].url の文字列を取得するには

(エラー内容)

~/zig/scoop-01>./run.sh
set -e
+ set -e     
zig version  
+ zig version
0.11.0
zig run main.zig  
+ zig run main.zig
main.zig:2:21: error: root struct of file 'net' has no member named 'http'
const http = std.net.http.client;
             ~~~~~~~^~~~~
referenced by:
    main: main.zig:7:18
    callMain: C:\Users\user\scoop\apps\zig\current\lib\std\start.zig:574:32
    remaining reference traces hidden; use '-freference-trace' to see all reference traces
exit status 1
~/zig/scoop-01>
0Like

zig言語で https://raw.githubusercontent.com/ScoopInstaller/Main/master/bucket/7zip.json にアクセスして、テキストを読み取り JSON 変数 json に格納した上で、json.architecture["64bit"].url の文字列を取得するには

こんなんでどうでしょう。

main.zig
const std = @import("std");
const allocator = std.heap.page_allocator;

pub fn main() !void {
    const uri = try std.Uri.parse("https://raw.githubusercontent.com/ScoopInstaller/Main/master/bucket/7zip.json");
    var client: std.http.Client = .{ .allocator = allocator };
    defer client.deinit();
    var request = try std.http.Client.request(&client, std.http.Method.GET, uri, .{ .allocator = allocator }, .{});
    defer request.deinit();
    try request.start();
    try request.wait();
    try std.testing.expect(request.response.status == .ok);
    var buffer = try allocator.alloc(u8, 256);
    defer allocator.free(buffer);
    var json_builder = std.ArrayList(u8).init(allocator);
    defer json_builder.deinit();
    while (true) {
        var size = try request.read(buffer);
        try json_builder.appendSlice(buffer[0..size]);
        if (size == 0) break;
    }
    var json: []u8 = json_builder.items;
    std.debug.print("json: {s}\n", .{json});
    var json_stream = std.io.fixedBufferStream(json);
    var json_stream_reader = json_stream.reader();
    var json_reader = std.json.reader(allocator, json_stream_reader);
    var parsed_json = try std.json.Value.jsonParse(allocator, &json_reader, .{});
    std.debug.print("-----\n", .{});
    var iterator = parsed_json.object.iterator();
    while (iterator.next()) |kv|
        std.debug.print("{s}\n", .{kv.key_ptr.*});
    std.debug.print("-----\n", .{});
    std.debug.print("version: {s}\n", .{parsed_json.object.get("version").?.string});
    std.debug.print("architecture['64bit'].url: {s}\n", .{parsed_json.object.get("architecture").?.object.get("64bit").?.object.get("url").?.string});
}
1Like

zig言語で https://raw.githubusercontent.com/ScoopInstaller/Main/master/bucket/7zip.json にアクセスして、テキストを読み取り JSON 変数 json に格納した上で、json.architecture["64bit"].url の文字列を取得するには

こんなんでどうでしょう。

@aktokaji さん・・・

大作ですね!ありがとうございます。完璧ですね。
deprecated が多すぎて移植に手間取ってましたw

allocator を std.heap.GeneralPurposeAllocator に変更して実行するとJSONまわりでメモリリークが発生するので、確認用として微修正版を作ってみました。

JSON の解析結果をアロケートするのに std.heap.ArenaAllocator を使ってみています。
メモリをいちいち defer で開放したり、メモリリークのチェックをするのは大変なので、トップレベルの allocator を std.heap.ArenaAllocator にするのが良いかもと考えています。

    var json_arena = std.heap.ArenaAllocator.init(allocator);
    defer json_arena.deinit();
main.zig
const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();
    defer {
        const leaked = gpa.deinit();
        _ = leaked;
        //if (leaked == .leak) std.testing.expect(false) catch @panic("TEST FAIL");
    }
    const uri = try std.Uri.parse("https://raw.githubusercontent.com/ScoopInstaller/Main/master/bucket/7zip.json");
    var client: std.http.Client = .{ .allocator = allocator };
    defer client.deinit();
    var request = try std.http.Client.request(&client, std.http.Method.GET, uri, .{ .allocator = allocator }, .{});
    defer request.deinit();
    try request.start();
    try request.wait();
    try std.testing.expect(request.response.status == .ok);
    var buffer = try allocator.alloc(u8, 256);
    defer allocator.free(buffer);
    var json_builder = std.ArrayList(u8).init(allocator);
    defer json_builder.deinit();
    while (true) {
        var size = try request.read(buffer);
        try json_builder.appendSlice(buffer[0..size]);
        if (size == 0) break;
    }
    var json: []u8 = json_builder.items;
    std.debug.print("json: {s}\n", .{json});
    var json_stream = std.io.fixedBufferStream(json);
    var json_reader = std.json.reader(allocator, json_stream.reader());
    defer json_reader.deinit();
    var json_arena = std.heap.ArenaAllocator.init(allocator);
    defer json_arena.deinit();
    var parsed_json = try std.json.Value.jsonParse(json_arena.allocator(), &json_reader, .{});
    std.debug.print("-----\n", .{});
    var iterator = parsed_json.object.iterator();
    while (iterator.next()) |kv|
        std.debug.print("{s}\n", .{kv.key_ptr.*});
    std.debug.print("-----\n", .{});
    std.debug.print("version: {s}\n", .{parsed_json.object.get("version").?.string});
    std.debug.print("architecture['64bit'].url: {s}\n", .{parsed_json.object.get("architecture").?.object.get("64bit").?.object.get("url").?.string});
}
1Like

allocator を std.heap.GeneralPurposeAllocator に変更して実行するとJSONまわりでメモリリークが発生するので、確認用として微修正版を作ってみました。

defer json_reader.deinit();

が、まず抜けてましたね。

parsed_json については開放の仕方がわからないので放り投げてましたw

メモリリークの確認方法と std.heap.ArenaAllocator でヒープからアロケートしたメモリを一括で開放する方法がわかってありがたかったです。

1Like

Your answer might help someone💌