I'm using an external C API from C++, where functions report an error by setting a global error state that needs to be queried manually after each function call.
In order to avoid doing this manually each time I'm using a macro to wrap the function calls, which looks similar to this:
#define CHECK(_call_) \
do { \
_call_; \
int err = LastError(); \
if(err != 0) throw Error(err, __FILE__, __LINE__); \
} while(0)
used like CHECK(ExternalFct(1, 2, 3)).
But this does not work for functions that return a value. In order to support this, a solution that seemed to work is to create and call a temporary lambda, containing an object that checks the error in its destructor:
#define CHECK(_call_) \
([&] { \
struct ErrorChecker { \
~ErrorChecker() noexcept(false) { \
int err = LastError(); \
if(err != 0) throw Error(err, __FILE__, __LINE__); \
} \
} errorChecker; \
return _call_; \
}())
It uses the fact that return <expression> is allowed even if the expression is void.
This seems to work, but looks like it could cause problems, mainly due to the capture-all lambda (needed to allow local variables inside the call expression), and the destructor which throws exceptions.
Are there situations in which this construct would cause problems (or unnecessary overhead), and is there a better way to make a single CHECK() macro that would work with both void and non-void functions?
I like your variant better, but if you want to get rid of destructor, you can do:
#define CHECK(_call_) \
([&]<typename T = decltype(_call_)> { \
if constexpr (std::is_void_v<T>) { \
_call_; \
int err = LastError(); \
if(err != 0) throw Error{err, __FILE__, __LINE__}; \
return; \
} else { \
T result = _call_; \
int err = LastError(); \
if(err != 0) throw Error{err, __FILE__, __LINE__}; \
return result; \
} \
}())
If you stick with macros, I would suggest renaming CHECK() to something more like CHECK_NO_RETURN(), and then defining a separate macro to handle returns, ie:
#define CHECK_NO_RETURN(_call_) \
do { \
_call_; \
int err = LastError(); \
if(err != 0) throw Error(err, __FILE__, __LINE__); \
} while(0)
#define CHECK_THEN_RETURN(_call_) \
do { \
auto ret = _call_; \
int err = LastError(); \
if(err != 0) throw Error(err, __FILE__, __LINE__); \
return ret; \
} while(0)
CHECK_NO_RETURN(ExternalFct1(1, 2, 3));
CHECK_THEN_RETURN(ExternalFct2(1, 2, 3));
Otherwise, I would suggest changing CHECK() into a variadic template function instead, eg:
#include <type_traits>
template<typename R, typename... Args>
inline typename std::enable_if<!std::is_void<R>::value, R>::type
Check(R (&call)(Args...), Args... args)
{
R ret = call(args...);
int err = LastError();
if (err != 0) throw Error(err, __FILE__, __LINE__);
return ret;
}
template<typename... Args>
inline void Check(void (&call)(Args...), Args... args)
{
call(args...);
int err = LastError();
if (err != 0) throw Error(err, __FILE__, __LINE__);
}
Check(ExternalFct1, 1, 2, 3);
return Check(ExternalFct2, 1, 2, 3);
Online Demo
Alternatively, in C++17 and later:
#include <type_traits>
template<typename R, typename... Args>
inline auto Check(R (&call)(Args...), Args... args)
{
if constexpr (!std::is_void_v<R>)
{
R ret = call(args...);
int err = LastError();
if (err != 0) throw Error(err, __FILE__, __LINE__);
return ret;
}
else
{
call(args...);
int err = LastError();
if (err != 0) throw Error(err, __FILE__, __LINE__);
}
}
Online Demo
Related
I want to implement a multiplatform plugin system on an application that I am working, but I am unable to make it work on Windows.
The proposal of this plugin system is to add the posibility of to compile the library and load it in the main program without to have to recompile it (dynamic load).
I have modified an example I have found in internet, and it compiles and works without problem in Linux, but on Windows it crash when the load function is executed.
My code looks like this:
export.h
#ifndef _SHARED_EXPORTS_H__
#define _SHARED_EXPORTS_H__
#ifdef _WIN32
#include <windows.h>
#include <string>
#define LIBLOAD(x) LoadLibraryA(x)
#define dlclose(x) FreeLibrary((HMODULE)x)
#define dlsym(x, y) GetProcAddress((HINSTANCE)x, y)
char *dlerror()
{
DWORD errorMessageID = GetLastError();
if (errorMessageID == 0)
{
return NULL; // No error message has been recorded
}
LPSTR messageBuffer = nullptr;
// Ask Win32 to give us the string version of that message ID.
// The parameters we pass in, tell Win32 to create the buffer that holds the message for us (because we don't yet know how long the message string will be).
size_t size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
// Copy the error message into a std::string.
std::string message(messageBuffer, size);
// Free the Win32's string's buffer.
LocalFree(messageBuffer);
char *cstr = new char[message.length() + 1];
strcpy(cstr, message.c_str());
// char *cstr = (char *)message.c_str();
fprintf(stderr, "Error: %s\n\n", cstr);
return cstr;
}
#ifdef BUILD_LIB
#define SHARED_EXPORT __declspec(dllexport)
#else
#define SHARED_EXPORT __declspec(dllimport)
#endif
#else
#include <dlfcn.h>
#define SHARED_EXPORT
#define LIBLOAD(x) dlopen(x, RTLD_LAZY)
#endif
#endif /* _SHARED_EXPORTS_H__ */
main.cpp
/*
*
* Main application which will load the plugins dinamically
*
*/
#include <vector>
#include "plugin_handler.hpp"
#ifdef _WIN32
#define EXT ".dll"
#else
#define EXT ".so"
#endif
int main()
{
auto plugins = load_plugins("plugins/", EXT);
for (auto ph : plugins)
{
fprintf(stderr, "Loading plugin...\n");
auto plugin = ph.load();
if (plugin == NULL)
{
fprintf(stderr, "The plugin is not loaded correctly\n");
continue;
}
fprintf(stderr, "Plugin loaded\n");
fprintf(stderr, "Auto loaded plugin: %s, version: %s\n", ph.get_name().c_str(), ph.get_version().c_str());
fprintf(stderr, "Running plugins command method:\n");
fprintf(stderr, "%s\n", plugin->command("Command here", "options here").c_str());
}
return 0;
}
plugin_handler.hpp
#include <string>
#include "plugin.hpp"
#include <filesystem>
class PluginHandler
{
std::shared_ptr<Plugin> (*_load)() = NULL;
void *handle = NULL;
char *(*_get_name)() = NULL;
char *(*_get_version)() = NULL;
char *last_error = NULL;
std::shared_ptr<Plugin> instance;
public:
PluginHandler(std::string name)
{
handle = LIBLOAD(name.c_str());
if (!handle || ((last_error = dlerror()) != NULL))
{
// Maybe the last_error variable is NULL because the handler is empty directly.
// In that case, try to return the error again
if (last_error == NULL)
{
last_error = dlerror();
}
// If the error still null here, then just add a general error text
if (last_error == NULL)
{
last_error = (char *)"Handler is empty. Maybe the library file is damaged.";
}
fprintf(stderr, "There was an error loading the %s lib:\n%s\n", name.c_str(), last_error);
return;
}
dlerror(); /* Clear any existing error */
_load = (std::shared_ptr<Plugin>(*)())dlsym(handle, "load");
if (!_load)
{
printf("La cagaste\n");
}
if ((last_error = dlerror()) != NULL)
{
fprintf(stderr, "Error getting the load symbol in the %s lib:\n%s\n", name.c_str(), last_error);
return;
}
_get_name = (char *(*)())dlsym(handle, "name");
if ((last_error = dlerror()) != NULL)
{
fprintf(stderr, "Error getting the name symbol in the %s lib:\n%s\n", name.c_str(), last_error);
return;
}
_get_version = (char *(*)())dlsym(handle, "version");
if ((last_error = dlerror()) != NULL)
{
fprintf(stderr, "Error getting the version symbol in the %s lib:\n%s\n", name.c_str(), last_error);
return;
}
}
~PluginHandler()
{
instance.reset();
if (handle != NULL)
{
dlclose(handle);
}
}
std::string get_name()
{
return std::string(_get_name());
}
std::string get_version()
{
return std::string(_get_version());
}
std::shared_ptr<Plugin> load()
{
if (!instance && _load != NULL)
{
fprintf(stderr, "Iniatilizing the class %d\n", _load);
instance = _load();
fprintf(stderr, "Initialized...\n");
}
return instance;
}
bool has_error()
{
if (last_error != NULL)
{
return true;
}
return false;
}
char *get_error()
{
if (last_error == NULL)
{
return (char *)'\0';
}
else
{
return last_error;
}
}
// Use it under your risk... If an error was set maybe something happens.
void clear_error()
{
last_error = NULL;
}
};
std::vector<PluginHandler> load_plugins(std::string path, std::string extension)
{
std::vector<PluginHandler> plugins;
for (auto &p : std::filesystem::recursive_directory_iterator(path))
{
if (p.path().extension() == extension)
{
PluginHandler plugin = PluginHandler(p.path().string());
if (!plugin.has_error())
{
plugins.push_back(plugin);
}
else
{
fprintf(stderr, "There was an error loading the plugin %s\n", p.path().string().c_str());
}
}
}
return plugins;
}
plugin.hpp
/*
This header file is the virtual plugin definition which will be used in derivated plugins and main program
*/
#include "export.h"
#include <string>
#include <memory>
class Plugin
{
public:
Plugin(){};
virtual ~Plugin(){};
virtual std::string command(std::string command, std::string options) { return ""; }
};
#define DEFINE_PLUGIN(classType, pluginName, pluginVersion) \
extern "C" \
{ \
std::shared_ptr<Plugin> SHARED_EXPORT load() \
{ \
fprintf(stderr, "Creating the pointer\n"); \
std::shared_ptr<Plugin> output = std::make_shared<classType>(); \
fprintf(stderr, "Pointer was created. Returning it...\n"); \
return output; \
} \
\
const char SHARED_EXPORT *name() \
{ \
return pluginName; \
} \
\
const char SHARED_EXPORT *version() \
{ \
return pluginVersion; \
} \
}
plugin1.cpp
#include "plugin.hpp"
#include <iostream>
class SHARED_EXPORT Plugin1 : public Plugin
{
public:
virtual std::string command(std::string command, std::string options)
{
return command + " " + options;
}
};
DEFINE_PLUGIN(Plugin1, "Plugin1", "0.0.1")
I am compiling both versions on Linux and the commands are:
Linux .so
g++ -fPIC -c plugin1.cpp -o plugin1.o
g++ -shared -o plugins/plugin1.so plugin1.o
g++ main.cpp -ldl -std=c++17 -o main
Windows .dll
x86_64-w64-mingw32-g++ -fPIC -DBUILD_LIB -g -static-libgcc -static-libstdc++ -c plugin1.cpp -o plugin1.o -Wl,--out-implib,plugin1.a
x86_64-w64-mingw32-g++ -DBUILD_LIB -g -shared -static-libgcc -static-libstdc++ -o plugins/plugin1.dll plugin1.o
x86_64-w64-mingw32-g++ main.cpp -g -static-libgcc -static-libstdc++ -std=c++17 -o main.exe
On linux the execution works fine:
$ ./main
Loading plugin...
Iniatilizing the class -2057853339
Creating the pointer
Pointer was created. Returning it...
Initialized...
Plugin loaded
Auto loaded plugin: Plugin1, version: 0.0.1
Running plugins command method:
Command here options here
But on Windows looks like it loads the dll library, but on "load" function execution it just crash:
>main.exe
Loading plugin...
Iniatilizing the class 1801459034
(Here returns to command line again)
Looks like the problem is when it tries to execute the "load" function, because It doesn't executes the first print I have added into that function. The problem is that I don't know where is the problem and how to debug it. I have noticed that in every execution the handler is the same, so maybe the library is on memory and is not unloaded or maybe is not even loading it and is failing. It is supposed to be NULL if fails, but now I am not sure if it is working.
What I am doing wrong?
Best regards!
When you call dlclose from ~PluginHandler the code of the shared object can be deleted from the address space, so calling any functions from the shared object can lead to segmentation fault. Possible fix:
## -67,7 +67,7 ##
instance.reset();
if (handle != NULL)
{
- dlclose(handle);
+// dlclose(handle);
}
}
Finally I have found the way to do it and I have fixed some mistakes I made.
export.h
#ifndef _SHARED_EXPORTS_H__
#define _SHARED_EXPORTS_H__
#ifdef _WIN32
#include <windows.h>
#include <string>
#define LIBLOAD(x) LoadLibrary(x)
#define dlclose(x) FreeLibrary((HMODULE)x)
#define dlsym(x, y) GetProcAddress((HINSTANCE)x, y)
char *dlerror()
{
DWORD errorMessageID = GetLastError();
if (errorMessageID == 0)
{
return NULL; // No error message has been recorded
}
LPSTR messageBuffer = nullptr;
// Ask Win32 to give us the string version of that message ID.
// The parameters we pass in, tell Win32 to create the buffer that holds the message for us (because we don't yet know how long the message string will be).
size_t size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
// Copy the error message into a std::string.
std::string message(messageBuffer, size);
// Free the Win32's string's buffer.
LocalFree(messageBuffer);
char *cstr = new char[message.length() + 1];
strcpy(cstr, message.c_str());
// char *cstr = (char *)message.c_str();
fprintf(stderr, "Error: %s\n\n", cstr);
return cstr;
}
#ifdef BUILD_LIB
#define SHARED_EXPORT __declspec(dllexport)
#else
#define SHARED_EXPORT __declspec(dllimport)
#endif
#else
#include <dlfcn.h>
#define SHARED_EXPORT
#define LIBLOAD(x) dlopen(x, RTLD_LAZY)
#endif
#endif /* _SHARED_EXPORTS_H__ */
main.cpp
/*
*
* Main application which will load the plugins dinamically
*
*/
#include <vector>
#include "plugin_handler.hpp"
#ifdef _WIN32
#define EXT ".dll"
#else
#define EXT ".so"
#endif
int main()
{
auto plugins = load_plugins("plugins/", EXT);
for (auto ph : plugins)
{
fprintf(stderr, "Loading plugin...\n");
auto plugin = ph->load();
if (plugin == NULL)
{
fprintf(stderr, "The plugin is not loaded correctly\n");
continue;
}
fprintf(stderr, "Plugin loaded\n");
fprintf(stderr, "Auto loaded plugin: %s, version: %s\n", ph->get_name().c_str(), ph->get_version().c_str());
fprintf(stderr, "Running plugins command method:\n");
fprintf(stderr, "%s\n", plugin->command("Command here", "options here").c_str());
delete ph;
}
return 0;
}
plugin_handler.h
#include <string>
#include "plugin.hpp"
#include <filesystem>
#include <memory>
class PluginHandler
{
using allocClass = Plugin *(*)();
using deleteClass = void (*)(Plugin *);
using charPReturn = char *(*)();
allocClass _load = NULL;
deleteClass _unload = NULL;
void *handle;
charPReturn _get_name = NULL;
charPReturn _get_version = NULL;
char *last_error = NULL;
std::shared_ptr<Plugin> instance;
public:
PluginHandler(std::string name)
{
if (!(handle = LIBLOAD(name.c_str())))
{
last_error = dlerror();
// If the error still null here, then just add a general error text
if (last_error == NULL)
{
last_error = (char *)"Handler is empty. Maybe the library file is damaged.";
}
fprintf(stderr, "There was an error loading the %s lib:\n%s\n", name.c_str(), last_error);
return;
}
_load = reinterpret_cast<allocClass>(dlsym(handle, "load"));
if ((last_error = dlerror()) != NULL)
{
fprintf(stderr, "Error getting the load symbol in the %s lib:\n%s\n", name.c_str(), last_error);
return;
}
_unload = reinterpret_cast<deleteClass>(dlsym(handle, "unload"));
if ((last_error = dlerror()) != NULL)
{
fprintf(stderr, "Error getting the load symbol in the %s lib:\n%s\n", name.c_str(), last_error);
return;
}
_get_name = reinterpret_cast<charPReturn>(dlsym(handle, "name"));
if ((last_error = dlerror()) != NULL)
{
fprintf(stderr, "Error getting the name symbol in the %s lib:\n%s\n", name.c_str(), last_error);
return;
}
_get_version = reinterpret_cast<charPReturn>(dlsym(handle, "version"));
if ((last_error = dlerror()) != NULL)
{
fprintf(stderr, "Error getting the version symbol in the %s lib:\n%s\n", name.c_str(), last_error);
return;
}
}
~PluginHandler()
{
if (last_error != NULL)
{
delete[] last_error;
}
/*
if (handle != NULL)
{
dlclose(handle);
handle = NULL;
}
*/
}
std::string get_name()
{
return std::string(_get_name());
}
std::string get_version()
{
return std::string(_get_version());
}
std::shared_ptr<Plugin> load()
{
if (_load != NULL)
{
instance = std::shared_ptr<Plugin>(_load(), _unload);
return instance;
}
return NULL;
}
void unload()
{
if (_unload != NULL)
{
_unload(instance.get());
}
}
bool has_error()
{
if (last_error != NULL)
{
return true;
}
return false;
}
char *get_error()
{
if (last_error == NULL)
{
return (char *)'\0';
}
else
{
return last_error;
}
}
// Use it under your risk... If an error was set maybe something happens.
void clear_error()
{
delete[] last_error;
last_error = NULL;
}
};
std::vector<PluginHandler *> load_plugins(std::string path, std::string extension)
{
std::vector<PluginHandler *> plugins;
for (auto &p : std::filesystem::recursive_directory_iterator(path))
{
if (p.path().extension() == extension)
{
PluginHandler *plugin = new PluginHandler(p.path().string());
if (!plugin->has_error())
{
plugins.push_back(plugin);
}
else
{
fprintf(stderr, "There was an error loading the plugin %s\n", p.path().string().c_str());
}
}
}
return plugins;
}
plugin.hpp
#pragma once
/*
This header file is the virtual plugin definition which will be used in derivated plugins and main program
*/
#include "export.h"
#include <string>
#include <memory>
class Plugin
{
public:
virtual ~Plugin() = default;
virtual std::string command(std::string command, std::string options) = 0;
};
#define DEFINE_PLUGIN(classType, pluginName, pluginVersion) \
extern "C" \
{ \
SHARED_EXPORT classType *load() \
{ \
printf("Creating new class pointer\n"); \
return new classType(); \
} \
\
SHARED_EXPORT void unload(classType *ptr) \
{ \
delete ptr; \
} \
\
const char SHARED_EXPORT *name() \
{ \
return pluginName; \
} \
\
const char SHARED_EXPORT *version() \
{ \
return pluginVersion; \
} \
}
plugin1.cpp
#include "plugin.hpp"
#include <iostream>
class SHARED_EXPORT Plugin1 : public Plugin
{
public:
virtual std::string command(std::string command, std::string options)
{
return command + " " + options;
}
};
DEFINE_PLUGIN(Plugin1, "Plugin1", "0.0.1")
Works better now and all the functions works as expected on Linux and Windows. After fixing the real problem, I am not sure how was working on Linux because the object creation was on a function which was going out of scope as soon the object is created. After converting this object to a pointer, the program started to work. Maybe the other fixes also helped, but this was the main.
One think I don't understand, is why to free the library with dlclose at the object destruction created a segmentation fault when the program exits. Removing that line exits the program as expected, but I am afraid to create a memory leak there.
Best regards.
I am trying to use CUDA C for GPU computing, in particular matrix inversion problem. Meanwhile at the beginning of my code I have defined function. But, that seems to give me an error of "expected declation" at the line where I initiate "do".
I am new to C++ so haven't tried much.
#include<cublas_v2.h>
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#define cudacall(call)
do
{
cudaError_t err = (call);
if (cudaSuccess != err)
{
fprintf(stderr, "CUDA Error:\nFile = %s\nLine = %d\nReason = %s\n", __FILE__, __LINE__, cudaGetErrorString(err));
cudaDeviceReset();
exit(EXIT_FAILURE)
}
}
while (0);
"Expected Declaration"
Multi-line macros need to have a \ to indicate that they continue on the next line. I lined all of them up at the end; scroll to see them.
#define cudacall(call) \
do { \
cudaError_t err = (call); \
if (cudaSuccess != err) { \
fprintf(stderr, "CUDA Error:\nFile = %s\nLine = %d\nReason = %s\n", \
__FILE__, __LINE__, cudaGetErrorString(err)); \
cudaDeviceReset(); \
exit(EXIT_FAILURE) \
} \
} while (0);
In general, please avoid macros if you can. Use lambdas and higher-order functions instead:
template<class F>
void cudacall(F&& func) {
cudaError_t err = func();
if (cudaSuccess != err) {
fprintf(stderr, "CUDA Error:\nFile = %s\nLine = %d\nReason = %s\n",
__FILE__, __LINE__, cudaGetErrorString(err));
cudaDeviceReset();
exit(EXIT_FAILURE);
}
}
We can use it like this:
void dostuff() {
bool wasICalled = false;
cudacall([&]() {
// Code goes here
// We can access and modify local variables inside a lambda
wasICalled = true;
// Return the error
return cudaError_t{};
});
}
I know little about __attribute__ and __cyg_profile_function_enter. Of course, they are both GNU C features.
I'm learning C++ to compile Nginx modules. I always try to convert the C code samples to C++.
Here is a simple sample of C:
#include <stdio.h>
int depth_ = -1;
#ifdef __GNUC__
void __cyg_profile_func_enter(void *, void *) __attribute__((no_instrument_function));
void _cyg_profile_func_enter(void *, void *) __attribute__((no_instrument_function));
#define sustainable(fn, caller) \
do {\
printf("%d, %s: fn = %p, caller = %p\n", depth_, __FUNCTION__, fn, caller); \
} while(0)
void __cyg_profile_func_enter(void *fn, void *caller){
printf("Enter:\n");
depth_++;
sustainable(fn, caller);
}
void __cyg_profile_func_exit(void *fn, void *caller){
printf("Exit:\n");
depth_--;
sustainable(fn, caller);
}
#endif
void sustain(){
depth_ = 100;
}
int main(){
depth_ = 10;
sustain();
//Suture suture;
//suture.sultry();
return 0;
}
sh$ gcc -finstrument-functions ...
It displays Enter: 101, __cyg_profile_func_enter: fn = 0x400645, caller = 0x4006ba and Exit: 100, __cyg_profile_func_exit: fn = 0x400645, caller = 0x4006ba circularly
This is the C++ code:
#include <iostream>
using namespace std;
int depth_ = -1;
#ifdef __GNUC__
extern "C" {
void __cyg_profile_func_enter(void *, void *) __attribute__((no_instrument_function));
void __cyg_profile_func_exit(void *, void *) __attribute__((no_instrument_function));
#define sustainable(fn, caller) \
do{ \
printf("%d, %s: fn = %p, caller = %p\n", depth_, __FUNCTION__, fn, caller); \
} while(0)
void __cyg_profile_func_enter(void *fn, void *caller){
printf("Enter:\n");
depth_++;
sustainable(fn, caller);
}
void __cyg_profile_func_exit(void *fn, void *caller){
printf("Exit:\n");
depth_--;
sustainable(fn, caller);
}
}
#endif
void sustain(){
depth_ = 100;
}
class Suture
{
public:
void sultry(){
}
};
int main(int argc, char **argv){
sustain();
Suture suture;
suture.sultry;
}
Then I compile with
sh$ g++ -std=c++11 -finstrument-functions ....
It displays Enter: 2, __cyg_profile_func_enter: fn = 0x400925, caller = 0x40099b and Exit: 1, __cyg_profile_func_exit: fn = 0x400925, caller = 0x40099b circularly.
It's weird. Why the depth_ = 100 works with gcc but not with g++?
What function do you expect fn to be the address of? I'm not seeing function calls in main() that should take place after the assignment of depth_.
If you're seeing repeated calls at all, they must be due to library functions, which could well be performed before the depth_ = 100; assignment.
I have code :
#define int4 unsigned long long int
int4 mer_thread = tex2D(STexture, col, row);
printf("\nTexture[%d][%d] = %d", row, col, tex2D(STexture, col, row));
Error "error : no instance of overloaded function "tex2D" matches the argument list"
but if define int4 unsigned long int, it work fine.
My code creat texture:
void Creat_TexttureS(int4 _S[nmax][NMAX])
{
cudaArray* carray;
cudaChannelFormatDesc channel;
channel = cudaCreateChannelDesc<int4>();
cudaMallocArray(&carray, &channel, NMAX, nmax);
cudaMemcpyToArray(carray, 0, 0, _S, sizeof(int4)*NMAX*nmax, cudaMemcpyHostToDevice);
STexture.filterMode = cudaFilterModePoint;
STexture.addressMode[0] = cudaAddressModeWrap;
STexture.addressMode[1] = cudaAddressModeClamp;
cudaBindTextureToArray(STexture, carray);
}
Thanks for your help !!
Below is a worked example that demonstrates the storing of data of type long long int in a 2D texture of type int2, then how to retrieve it via tex2D() and re-interpret it as long long int.
#include <stdlib.h>
#include <stdio.h>
// Macro to catch CUDA errors in CUDA runtime calls
#define CUDA_SAFE_CALL(call) \
do { \
cudaError_t err = call; \
if (cudaSuccess != err) { \
fprintf (stderr, "Cuda error in file '%s' in line %i : %s.\n",\
__FILE__, __LINE__, cudaGetErrorString(err) ); \
exit(EXIT_FAILURE); \
} \
} while (0)
// Macro to catch CUDA errors in kernel launches
#define CHECK_LAUNCH_ERROR() \
do { \
/* Check synchronous errors, i.e. pre-launch */ \
cudaError_t err = cudaGetLastError(); \
if (cudaSuccess != err) { \
fprintf (stderr, "Cuda error in file '%s' in line %i : %s.\n",\
__FILE__, __LINE__, cudaGetErrorString(err) ); \
exit(EXIT_FAILURE); \
} \
/* Check asynchronous errors, i.e. kernel failed (ULF) */ \
err = cudaThreadSynchronize(); \
if (cudaSuccess != err) { \
fprintf (stderr, "Cuda error in file '%s' in line %i : %s.\n",\
__FILE__, __LINE__, cudaGetErrorString( err) ); \
exit(EXIT_FAILURE); \
} \
} while (0)
__forceinline__ __device__ long long int int2_as_longlong (int2 a)
{
long long int res;
asm ("mov.b64 %0, {%1,%2};" : "=l"(res) : "r"(a.x), "r"(a.y));
return res;
}
texture<int2, 2, cudaReadModeElementType> tex;
__global__ void kernel (int m, int n)
{
int2 data;
for (int row = 0; row < m; row++) {
for (int col = 0; col < n; col++) {
data = tex2D (tex, col, row);
printf ("% 11lld ", int2_as_longlong (data));
}
printf ("\n");
}
}
int main (void)
{
int m = 4; // height = #rows
int n = 3; // width = #columns
size_t pitch, tex_ofs;
unsigned long long int arr[4][3]=
{{11111111LL, 11112222LL, 11113333LL},
{22221111LL, 22222222LL, 22223333LL},
{33331111LL, 33332222LL, 33333333LL},
{44441111LL, 44442222LL, 44443333LL}};
int2 *arr_d = 0;
CUDA_SAFE_CALL(cudaMallocPitch((void**)&arr_d,&pitch,n*sizeof(*arr_d),m));
CUDA_SAFE_CALL(cudaMemcpy2D(arr_d, pitch, arr, n*sizeof(arr[0][0]),
n*sizeof(arr[0][0]),m,cudaMemcpyHostToDevice));
CUDA_SAFE_CALL (cudaBindTexture2D (&tex_ofs, &tex, arr_d, &tex.channelDesc,
n, m, pitch));
if (tex_ofs !=0) {
printf ("tex_ofs = %zu\n", tex_ofs);
return EXIT_FAILURE;
}
printf ("printing texture content\n");
kernel<<<1,1>>>(m, n);
CHECK_LAUNCH_ERROR();
CUDA_SAFE_CALL (cudaUnbindTexture (tex));
CUDA_SAFE_CALL (cudaFree (arr_d));
return EXIT_SUCCESS;
}
How can I get cerr to print 5 < 6 as opposed to statement_? I have access to Boost and Qt.
using namespace std;
#define some_func( statement_ ) \
if( ! statement_ ) \
{ \
throw runtime_error( "statement_" ); \
} \
int main()
{
try
{
some_func( 5 < 6 );
}
catch(std::exception& e)
{
cerr << e.what();
}
}
You need to use the stringize operator:
throw runtime_error(# statement_);
If statement_ may be a macro, you'll want to use the double stringize trick.
Oh, I found this.
and here's the final working code =):
#include <stdexcept>
#include <iostream>
#define some_func( statement_ ) \
if( ! statement_ ) \
{ \
throw std::runtime_error( #statement_ ); \
/* Note: #, no quotes! ^^^^^^^^^^ */ \
} \
int main(int argc, char** argv)
{
try
{
some_func( 5 < 6 );
}
catch(std::exception& e)
{
std::cerr << e.what();
}
}