I have the following code and get a compiling error:
#include <cstddef>
#include <cstdint>
#define CHECK_ALIGN(ptr, alignment) \
do{ \
constexpr size_t status \
= reinterpret_cast<uintptr_t>(ptr) % alignment; \
static_assert(status == 0, "ptr must be aligned"); \
}while(0)
int main(int argc, char** argv) {
char c;
int i;
long l ;
float f;
CHECK_ALIGN(&c, sizeof(c));
CHECK_ALIGN(&i, sizeof(i));
CHECK_ALIGN(&l, sizeof(l));
CHECK_ALIGN(&f, sizeof(f));
return 0;
}
error: conversion from pointer type 'char*' to arithmetic type 'uintptr_t' {aka 'long unsigned int'} in a constant expression
What is the proper type to convert to for those pointer type to do some arithmetic?
status cannot be constexpr because the value of ptr is not known at compile time. Also, static_assert() needs to be replaced with assert() for the same reason.
#include <cstddef>
#include <cstdint>
#include <cassert>
#define CHECK_ALIGN(ptr, alignment) \
do{ \
const size_t status \
= reinterpret_cast<uintptr_t>(ptr) % alignment; \
assert(status == 0); \
} while(0)
int main(int argc, char** argv) {
char c;
int i;
long l ;
float f;
CHECK_ALIGN(&c, sizeof(c));
CHECK_ALIGN(&i, sizeof(i));
CHECK_ALIGN(&l, sizeof(l));
CHECK_ALIGN(&f, sizeof(f));
return 0;
}
Godbolt: https://godbolt.org/z/GrWdE3sGK
Alternatively, you could use constexpr expressions like this:
#include <cstddef>
#include <cstdint>
#define CHECK_ALIGN(value, alignment) \
static_assert(alignof((value)) % alignment == 0, #value " must be aligned");
int main(int argc, char** argv) {
char c;
int i;
long l ;
float f;
CHECK_ALIGN(c, sizeof(c));
CHECK_ALIGN(i, sizeof(i));
CHECK_ALIGN(l, sizeof(l));
CHECK_ALIGN(f, sizeof(f));
return 0;
}
Godbolt: https://godbolt.org/z/fMfY3P9bd
Related
In C++ I'm trying to convert command line *argv[] pointer (3 arguments) to vector of unsigned chars i.e. mytest 148 64 127
I got a vector:
vector<unsigned char> msg;
Vector includes 3 unsigned chars : msg = {0, 0, 0}
When I trying to convert in this way,
unsigned char c1 = *argv[1];
unsigned char c2 = *argv[2];
unsigned char c3 = *argv[3];
msg = {c1, c2, c3}
I get only first character of these chars.
i.e.
In command line I enter : mytest 148 64 127
I get : 1, 6 and 1
I recommend creating a vector of strings:
#include <iostream>
#include <vector>
int
main(int argc, char *argv[]) {
std::vector<std::string> args;
for (int i = 1; i < argc; i++) {
args.push_back({ argv[i] });
}
for (auto a: args) {
std::cout << a << std::endl;
}
return 0;
}
Simplest is convert to using strings.
vector<string> msg;
If you really want unsigned chars, then you will need to do something like:
vector<vector <unsigned char>> msg;
Rather than copy the characters you can save pointers to argv by doing
vector<unsigned char *> msg;
msg.push_back(reinterpret_cast<unsigned char *>(argv[0]));
You are saving only the 1st char of each argument string into your vector.
unsigned char c1 = *argv[1];
Is the same as doing:
const char *str = argv[1];
unsigned char c1 = str[0]; // <-- 1st char only!
For what you are attempting, you need to instead parse each argument string as-is into the numeric value it represents, so that the argument strings "148" "64" "127" yield the integers 148 64 127. You can use std::stoi() or std::stol() for that, eg:
#include <vector>
#include <string>
//#include <cstdlib>
//#include <limits>
/*
static const int min_uc = std::numeric_limits<unsigned char>::min();
static const int max_uc = std::numeric_limits<unsigned char>::max();
*/
int main(int argc, char* argv[])
{
if (argc < 2)
{
// no arguments given, do something...
return 0;
}
std::vector<unsigned char> msg;
msg.reserve(argc-1);
for (int i = 1; i < argc; ++i)
{
int i = std::stoi(argv[i], nullptr, 0);
//int i = std::strtol(argv[i], nullptr, 0);
if ((i < 0) || (i > 255))
//if ((i < min_uc) || (i > max_uc))
{
// bad input, do something...
return 0;
}
msg.push_back(static_cast<unsigned char>(i));
}
// use msg as needed...
...
}
How can I convert it? And I want the converted result to 1.
#include <iostream>
#include <string>
int main(int argc, const char * argv[]) {
std::string s = "0x00";
// insert code here...
unsigned char* str_hex = (unsigned char*)s.c_str();
unsigned char target = 0x00;
std::cout << "result: " << (*str_hex == target) << "\n";
return 0;
}
Like this: // #include <string>
std::string s = "0x4A";
unsigned char ch = std::stoul(s, nullptr, 16); // 'J' (Since C++11)
Or like this: // #include <cstdio>
std::string s = "0x4B";
unsigned char ch = '\0';
sscanf(s.c_str(), "%x", &ch); // 'K' (C library function)
From what I have read, this function should work, but for the life of me, I cannot figure out why it isn't.
I override the invalid parameter handler so I can continue running if an invalid parameter is passed (such as a buffer that is too small).
asprintf_s macro takes the parameters of a standard sprintf_s, adds the filename and line number, then calls asprintf_s2. It checks to see if the result would have overflowed the buffer, prints the filename and the line of where the overflowed occurred.
Problem: I'm guessing I'm doing something wrong with the variadic parameters as it always returns an overflow.
Output of program below
#include "stdafx.h"
#include <iostream>
#include <stdio.h>
#include <string>
#include <excpt.h>
#include <stdarg.h>
#define asprintf_s(...) asprintf_s2( __FILE__, __LINE__, __VA_ARGS__)
//#define asprintf_s(...) sprintf_s( __VA_ARGS__ )
inline int asprintf_s2(char *file, int line, char *dest, int sizeOfDest, char *Format, ...)
{
va_list pArgs;
va_start(pArgs, Format);
int sizeOfBuffer = sprintf_s(dest, sizeOfDest, Format, pArgs);
if (sizeOfBuffer == -1) printf("Buffer Overflow! File: %s LINE: %d\n", file, line );
va_end(pArgs);
return sizeOfBuffer;
}
void in_house_invalid_parameter(
const wchar_t * expression,
const wchar_t * function,
const wchar_t * file,
unsigned int line,
uintptr_t pReserved
)
{
// Do nothing on invalid parameter
}
int main()
{
char temp1[3];
char temp80[80];
std::string input;
int k = -3;
_set_invalid_parameter_handler(in_house_invalid_parameter);
strcpy_s(temp1, sizeof(temp1), "XX");
strcpy_s(temp80, sizeof(temp80), "1");
printf("Temp1:'%s'\n", temp1);
k = asprintf_s(temp1, sizeof(temp1), "%s\n", temp80);
printf("k:%d temp1:'%s', temp80:'%s'\n", k, temp1, temp80);
std::getline(std::cin, input);
return 0;
}
You just have to use vsprintf or vsprintf_s function
Edit: or vasprintf for your case
My purpose is quite simple: when I start the mongoose server, the server will initialize a variable which is defined by me. To do this, I hooked __libc_start_main. Then when the server receives a request, it will print out that initialized variable. To do this, I hooked recv. Below is my code.
#include <string>
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#include "common-structure.h"
# define dprintf(fmt...)
data datainfo; //defined in common-structure.h
typedef int (*main_type)(int, char**, char**);
struct arg_type
{
char **argv;
int (*main_func) (int, char **, char **);
};
main_type saved_init_func = NULL;
void tern_init_func(int argc, char **argv, char **env){
dprintf("%04d: __tern_init_func() called.\n", (int) pthread_self());
if(saved_init_func)
saved_init_func(argc, argv, env);
datainfo.age = 10;
}
typedef void (*fini_type)(void*);
fini_type saved_fini_func = NULL;
extern "C" int my_main(int argc, char **pt, char **aa)
{
int ret;
arg_type *args = (arg_type*)pt;
dprintf("%04d: __libc_start_main() called.\n", (int) pthread_self());
ret = args->main_func(argc, args->argv, aa);
return ret;
}
extern "C" int __libc_start_main(
void *func_ptr,
int argc,
char* argv[],
void (*init_func)(void),
void (*fini_func)(void),
void (*rtld_fini_func)(void),
void *stack_end)
{
typedef void (*fnptr_type)(void);
typedef int (*orig_func_type)(void *, int, char *[], fnptr_type,
fnptr_type, fnptr_type, void*);
orig_func_type orig_func;
arg_type args;
void * handle;
int ret;
// Get lib path.
Dl_info dli;
dladdr((void *)dlsym, &dli);
std::string libPath = dli.dli_fname;
libPath = dli.dli_fname;
size_t lastSlash = libPath.find_last_of("/");
libPath = libPath.substr(0, lastSlash);
libPath += "/libc.so.6";
libPath = "/lib/x86_64-linux-gnu/libc.so.6";
if(!(handle=dlopen(libPath.c_str(), RTLD_LAZY))) {
puts("dlopen error");
abort();
}
orig_func = (orig_func_type) dlsym(handle, "__libc_start_main");
if(dlerror()) {
puts("dlerror");
abort();
}
dlclose(handle);
dprintf("%04d: __libc_start_main is hooked.\n", (int) pthread_self());
args.argv = argv;
args.main_func = (main_type)func_ptr;
saved_init_func = (main_type)init_func;
saved_fini_func = (fini_type)rtld_fini_func;
ret = orig_func((void*)my_main, argc, (char**)(&args),
(fnptr_type)tern_init_func, (fnptr_type)fini_func,
rtld_fini_func, stack_end);
return ret;
}
//hook recv
extern "C" ssize_t recv(int sockfd, void *buf, size_t len, int flags)
{
ssize_t (*orig_recv)(int sockfd, void *buf, size_t len, int flags);
orig_recv = dlsym(RTLD_NEXT, "recv");
orig_recv(sockfd, buf, len, flags);
printf("age is %d\n", datainfo.age);
}
However, when I makefile, I get the error: invalid conversion from ‘void*’ to ‘ssize_t (*)(int, void*, size_t, int) coming from dlsym(RTLD_NEXT, "recv");. My another question is can I achieve my goal in this way? If not, what is the correct way?
C++ is much more strongly typed than C, you need to explicitly cast void * to the correct type.
For example:
extern "C" ssize_t recv(int sockfd, void *buf, size_t len, int flags)
{
using orig_recv_t = ssize_t (*)(int, void *, size_t, int);
// Or for pre C++11 compilers: typedef ssize_t (*orig_recv_t)(int, void *, size_t, int);
orig_recv_t orig_recv;
orig_recv = reinterpret_cast<orig_recv_t>(dlsym(RTLD_NEXT, "recv"));
orig_recv(sockfd, buf, len, flags);
printf("age is %d\n", datainfo.age);
}
code :
#include <stdarg.h>
#include <string>
#include <iostream>
std::wstring string_format(const std::wstring &fmt, ...) {
int size = 100;
std::wstring str;
va_list ap;
while (1) {
str.resize(size);
va_start(ap, fmt);
int n = vsnwprintf((wchar_t *)str.c_str(), size, fmt.c_str(), ap);
va_end(ap);
if (n > -1 && n < size) {
str.resize(n);
return str;
}
if (n > -1) size = n + 1;
else size *= 2;
}
return str;
}
std::wstring printf_wrapper(std::wstring text, ...) {
using namespace std;
va_list args;
va_start(args, text);
wstring formatted_text = string_format(text, args);
va_end (args);
return formatted_text;
}
int main(int argc, char *argv[])
{
using namespace std;
wcout << printf_wrapper(L"example%d",1) << endl;
return 0;
}
and it returns : example2293384
the function is from here: https://stackoverflow.com/a/8098080/393087
origin of this code is from the documentation of vsnprintf: http://www.tin.org/bin/man.cgi?section=3&topic=vsnprintf
You cannot "forward" varargs like that. So string_format needs to take a va_list as its 2nd argument, not ....