Utilizing C in WebAssembly to return string values

Is it possible to retrieve a JavaScript string from a WebAssembly function?

https://dev.to/azure/passing-strings-from-c-to-javascript-in-web-assembly-1p01 - not functional

C

#include <stdio.h>
#include <string.h>

void jsPrintString(const char *s, uint16_t len);

void print() {
  const char* str = "Hello from C++!";
  jsPrintString(str, strlen(str));
}

Compiler:

emcc -Os start.c  -s STANDALONE_WASM -s EXPORTED_FUNCTIONS="['_hello']" -s ERROR_ON_UNDEFINED_SYMBOLS=0 -Wl,--no-entry -o "test.wasm"

Javascript:

const memory = new WebAssembly.Memory({ initial: 1 });

    function handlePrintString (offset, length) {
      console.log(offset, length);
      const bytes = new Uint8Array(memory.buffer, offset, length);
      const string = new TextDecoder('utf8').decode(bytes);
      console.log(string); //empty ???????????????????????????????????
    }

    const importObject = {
      env: {
        jsPrintString: handlePrintString,
        memory: memory
      },

      js: { mem: memory }
    };

    WebAssembly.instantiateStreaming(fetch('/js/test.wasm'), importObject)
      .then(obj => {
        console.log(obj.instance.exports);
        console.log(obj.instance.exports.print());
      });

memory ArrayBuffer [0,0,0,0,0,0,0,0,0,0,0.....] ???

Answer №1

Is it possible to retrieve a JavaScript string from within a WebAssembly function?

No, this is not directly possible. The approach involves copying the string to memory that is shared with JavaScript.

void hello(char *array) {
    const my_string = "Hello from C++!";
    memcpy(array, my_string, strlen(my_string));
}
  (async () => {
    const response = await fetch('/js/test.wasm');
    const bytes = await response.arrayBuffer();
    const results = await WebAssembly.instantiate(bytes, {});
    const { instance: { exports: { memory, hello } }} = results;
    const array = new Uint8Array(memory.buffer, 0, 15);
    hello(array.byteOffset);
    console.log(new TextDecoder('utf8').decode(array)); // Hello from C++!
  })();

Answer №2

You're on the right track with your code, it's definitely possible to achieve what you're suggesting. Contrary to the top comment, you don't need to explicitly copy to shared memory. You can find a more detailed explanation in this blog post here.

Sample C code:

const char* getString() {
  return "Hello World!";
}

To compile, use:

clang --target=wasm32 -nostdlib -Wl,--no-entry -Wl,--export-all -o main.wasm main.c

And for JS code:

var importObject = { imports: { imported_func: arg => console.log(arg) } };

WebAssembly.instantiateStreaming(fetch('main.wasm'), importObject)
.then(obj => {

  var charArray = new Int8Array(
    obj.instance.exports.memory.buffer, // Accessing WASM memory
    obj.instance.exports.getString(), // Pointer to char
    12                                 // Length of string
  );

  // Convert ASCII code to char
  let string = String.fromCharCode.apply(null, charArray) 
  console.log(string);
});

Answer №3

The most effective answer comes from Iron Toad as it directly addresses the original question. I am puzzled as to why no one has upvoted it yet.

In this scenario, transitioning to Typescript would be more efficient by replacing

String.fromCharCode.apply(null, charArray)
with
TextDecoder('utf8').decode(charArray)
to avoid any type warnings from the ts compiler.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Adding markers to a Leaflet map using coordinates retrieved from a Supabase database - a step-by-step guide

I am looking to incorporate markers on a map using coordinates stored in a Supabase database column. Below is my Vue code: <l-marker v-for="(marker, index) in markers" :key="index" ref="markersRef" :lat-lng="marker.po ...

Error in AngularJS ng-repeat syntax

As a newcomer to AngularJS, I ventured into creating a Bootstrap form with a loop but encountered an error. What could be the mistake I made? <form class="form-horizontal" role="form" name="newForm" novalidate ng-controller="newFormController"> < ...

Ways to populate a dropdown menu by choosing a value from a different dropdown menu

Is there a way to create a dropdown list of employees by choosing the department from another dropdown menu in HTML? I need to display a list of employees who belong to the selected department in the second dropdown list. ...

Is it possible to append an "index" to a database field using Express, Loopback, or NodeJS?

Currently, we are utilizing the Express/Loopback Framework for our backend. I am currently working on ensuring that indexes on certain fields in models are properly created in MongoDB. Is there a way to utilize meta-tags within the models so that DataJuggl ...

Problem with locating elements using Selenium xpath

While using selenium and xpath, I encountered a peculiar issue. On a page, there are 25 <a> tags with nested <img/> tags. I am trying to retrieve all these elements using the findElements() method. Interestingly, upon inspecting the page source ...

Issue with npm during installation of REACT - not functioning as expected

After executing all the necessary commands on the command line, including globally installing npm with npm install -g create-react-app, as well as running npx create-react-app <myprojectname> and clearing the npm cache, I consistently encountered an ...

Using ExpressJS to generate a page with inputs

Using ExpressJS, I have created an Object of the IndexController in my router (index.js) and passed a String as a constructor argument. I then attempted to call the showDefaultFeed method. Expected output from "index.hbs" view was to print the argument pa ...

generating a dynamic string array containing particular elements

Given a string "hello @steph the email you requested is [email protected] for user @test" The goal is to transform it into: ['hello ', <a href="">@steph</a>, 'the email you requested is <a href="/cdn-cgi/l/email-protect ...

VS code is showing the directory listing instead of serving the HTML file

Recently, I attempted to use nodejs to serve the Disp.html file by following a code snippet from a tutorial I found on YouTube. const http = require("http"); const fs = require("fs"); const fileContent = fs.readFileSync("Disp.html& ...

In a JavaScript project, encountering an error when using FB.logout that states "The expression is undefined and not a function."

Seeking to integrate Login with FB into my react website. FB.init({ appId : app_id, cookie : true, xfbml : true, version : 'v5.0' }); Followed by FB.getLoginStatus(({status}) => { if (status === 'conn ...

Differences in outcomes have been observed between the elementLocated and findElements functions

Currently, I am in the process of developing Webdriver automation for a specific web application. As part of this process, I have created a test that seems to be functioning well most of the time but occasionally encounters an issue. it('verifies pre ...

Is it possible to perform a legitimate POST request using AJAX XMLHttpRequest, rather than the traditional var=val URL type post?

Apologies for the unclear question, but here is my query... I recently began using Ajax and encountered an issue with sending XMLHttpRequest in the background. I am facing problems with certain html special characters in the form data, especially the & ...

Comparing throwing exceptions in Node.js and Gevent

During a recent tech gathering, I heard an interesting claim about the behavior of callbacks and exceptions in Node.js and Gevent. The person mentioned that if a callback throws an exception in Node.js, it can crash the entire process, whereas in Gevent, a ...

jQuery function to automatically close any other opened divs when a new div is opened

I have multiple elements that reveal a div when clicked. The issue is that if all elements are clicked, all divs open instead of just the one that was clicked. This is my jQuery code: <script> $(document).ready(function() { $('.servicemark ...

Executing a search and replace function using a delay within a foreach loop - the ultimate guide

Below is a snippet of code where I attempt to perform find and replace within an array by searching for keys and replacing them with corresponding values. However, the expected functionality does not work as intended, leading to multiple searches for &apos ...

Exploring Wi-Fi functionalities with Android NDK

Is it possible to utilize WIFI features in Android using c code with the assistance of NDK without relying on Java API for WIFI? Despite searching on Google and stackoverflow, I have been unable to find any examples. I am curious to know if this is achieva ...

What is the best way to test a React component that includes a Router, Redux, and two Higher Order Components using Jest and Enzyme?

I'm currently facing a challenge with this issue. I have a React Component that is linked to React Router 4 and Redux store, and it's wrapped by two HOCs. It may sound complicated, but that's how it was implemented. Here's the export st ...

Make the child div images disappear gradually and at the same time, make an overlapping parent div image appear using Javascript

Check out my attempt at solving this challenge on jsfiddle: http://jsfiddle.net/oca3L32h/ In the scenario, there are 3 divs within a main div. Each of these divs contains an image and they overlap each other. By using radio buttons, the visibility of the ...

Leverage variables in JavaScript to establish a unique style

function AdjustScale(){ scaleX = window.innerWidth / 1024; scaleY = window.innerHeight / 768; element = document.getElementById("IFM"); element.style.transform = "scale(" + scaleX + ", " + scaleY + ")"; } I'm facing an issue with thi ...

Trouble with controlling the speed of ajax requests while using vue-multiselect and lodash

I am working on a Vue application that includes a vue-multiselect component. My goal is to load the multiselect options via ajax. To achieve this, I am using lodash.throttle to limit the frequency of ajax requests as the user types in the search criteria ...