mersenneforum.org  

Go Back   mersenneforum.org > Extra Stuff > Programming

Reply
 
Thread Tools
Old 2019-06-26, 22:48   #1
ixfd64
Bemusing Prompter
 
ixfd64's Avatar
 
"Danny"
Dec 2002
California

2·17·67 Posts
Default Simple C/C++ programming questions (mostly about arrays)

I recently started working on small improvements for mfakto. I'm a little embarrassed to ask these questions, but it's been quite a while since I worked with C/C++.

1. How can I do a foreach loop through an array of C strings in C++?

I'm defining strings using char pointers (to keep consistency with mfakto) and arrays of strings like this:

Code:
char *str_arr[] = {
"blah",
"blah blah",
...
}
However, for (char *s : str_arr) results in a compiler error. What's the syntax of a foreach loop in this case?

2. I also want to get the number of elements in an array of strings. However, sizeof() always returns 8 as I'm defining strings using char pointers. sizeof(str_arr)/sizeof(str_arr[0]) doesn't work either and always returns 1. Is there another solution?

3. This is more of a question about style: I have an array of strings (mainly GPU names) that only need to be accessed once. Is it OK to move them to the header file?

Thanks!

Last fiddled with by ixfd64 on 2019-06-26 at 22:51
ixfd64 is online now   Reply With Quote
Old 2019-06-27, 01:54   #2
rogue
 
rogue's Avatar
 
"Mark"
Apr 2003
Between here and the

580010 Posts
Default

Quote:
Originally Posted by ixfd64 View Post
I recently started working on small improvements for mfakto. I'm a little embarrassed to ask these questions, but it's been quite a while since I worked with C/C++.

1. How can I do a foreach loop through an array of C strings in C++?

I'm defining strings using char pointers (to keep consistency with mfakto) and arrays of strings like this:

Code:
char *str_arr[] = {
"blah",
"blah blah",
...
}
However, for (char *s : str_arr) results in a compiler error. What's the syntax of a foreach loop in this case?

2. I also want to get the number of elements in an array of strings. However, sizeof() always returns 8 as I'm defining strings using char pointers. sizeof(str_arr)/sizeof(str_arr[0]) doesn't work either and always returns 1. Is there another solution?

3. This is more of a question about style: I have an array of strings (mainly GPU names) that only need to be accessed once. Is it OK to move them to the header file?

Thanks!
You can use vector<string> and add members to the vector in a constructor (or in main()). You can loop with an iterator object and use size() to get the number of elements. Here is an example (assuming I didn't fubar it in some way):

Code:
   vector<string>::iterator it = myVector.begin();
   string element;

   while (it != myVector.end())
   {
      element = *it;
      . . . do something with element . . .
      it++;
   }
You can also use a string (or char *) array like you have, but use NULL as the last member of the array.

You could also use:

Code:
char *str_arr[MY_ARRAY_SIZE] = {
"blah",
"blah blah",
...
}
and #define MY_ARRAY_SIZE if you know that the number of elements in the array won't change.

Question, why do you need an array of GPU names? Assuming that you are writing some logic in your C/C++ to determine which GPU code to execute, there must be some APIs where you can ask the GPU what features it supports.

BTW, is your source open? Is it possible that you could build your code upon the mtsieve framework (which supports OpenCL workers)? That might save you a lot of work if you are rewriting your C/C++.
rogue is offline   Reply With Quote
Old 2019-06-27, 07:07   #3
Nick
 
Nick's Avatar
 
Dec 2012
The Netherlands

22×353 Posts
Default

1. At a C level, if you mark the end of the array with a 0 (or NULL) then you could do it like this:
Code:
char *str_arr[ ] = { "blah", "blah blah", ...,0 };

int n;
for (n=0;str_arr[n];++n)
{ ...use str_arr[n]...

}
2. Do you mean the number of elements allocated or the number in use?
The basic C level array does not remember its own size.
You would have to store it separately (or use a constant value if it doesn't change).

3. If I remember correctly, putting initial values in a variable makes the declaration a definition which therefore reserves storage.
You don't want this to be done by every file including the header!

Last fiddled with by Nick on 2019-06-27 at 07:13 Reason: Typo
Nick is offline   Reply With Quote
Old 2019-06-27, 12:18   #4
Chris Card
 
Chris Card's Avatar
 
Aug 2004

3·43 Posts
Default

Quote:
Originally Posted by ixfd64 View Post
I recently started working on small improvements for mfakto. I'm a little embarrassed to ask these questions, but it's been quite a while since I worked with C/C++.

1. How can I do a foreach loop through an array of C strings in C++?

I'm defining strings using char pointers (to keep consistency with mfakto) and arrays of strings like this:

Code:
char *str_arr[] = {
"blah",
"blah blah",
...
}
However, for (char *s : str_arr) results in a compiler error. What's the syntax of a foreach loop in this case?

2. I also want to get the number of elements in an array of strings. However, sizeof() always returns 8 as I'm defining strings using char pointers. sizeof(str_arr)/sizeof(str_arr[0]) doesn't work either and always returns 1. Is there another solution?

3. This is more of a question about style: I have an array of strings (mainly GPU names) that only need to be accessed once. Is it OK to move them to the header file?

Thanks!
This works fine for me using gcc 8.3.1
Code:
#include <iostream>

int main(int argc, char* argv[])
{
    const char* str_arr[] = { "blah", "blah blah", "a b c d e" };
    for (const char* s : str_arr)
    {
        std::cout << s << std::endl;
    }

    return 0;
}
Chris Card is offline   Reply With Quote
Old 2019-06-27, 23:31   #5
ixfd64
Bemusing Prompter
 
ixfd64's Avatar
 
"Danny"
Dec 2002
California

2·17·67 Posts
Default

Quote:
Originally Posted by rogue View Post
Question, why do you need an array of GPU names? Assuming that you are writing some logic in your C/C++ to determine which GPU code to execute, there must be some APIs where you can ask the GPU what features it supports.

BTW, is your source open? Is it possible that you could build your code upon the mtsieve framework (which supports OpenCL workers)? That might save you a lot of work if you are rewriting your C/C++.
I'm trying to make the GPU detection code in mfakto more organized. Currently, the code looks like this:

Code:
if (strstr(deviceinfo.d_name, "Capeverde")  ||    // 7730, 7750, 7770, 8760, 8740, R7 250X
    strstr(deviceinfo.d_name, "Pitcairn")   ||    // 7850, 7870, 8870
    strstr(deviceinfo.d_name, "Bonaire")    ||    // 7790, R7 260, R7 260X
    strstr(deviceinfo.d_name, "Oland")      ||    // 8670, 8570, R9 240, R9 250
    strstr(deviceinfo.d_name, "Sun")        ||    // 85x0M
    strstr(deviceinfo.d_name, "Mars")       ||    // 86x0M, 87x0M
    strstr(deviceinfo.d_name, "Venus")      ||    // 88x0M
    strstr(deviceinfo.d_name, "Saturn")     ||    // 8930M, 8950M
    strstr(deviceinfo.d_name, "Neptune")    ||    // 8970M, 8990M
    strstr(deviceinfo.d_name, "Curacao")    ||    // R9 265, R9 270, R9 270X
    strstr(deviceinfo.d_name, "Tonga")      ||    // R9 285
    strstr(deviceinfo.d_name, "Hainan")      ||    // R9 285
    strstr(deviceinfo.d_name, "Kalindi")          // GCN APU, Kabini, R7 ???
    )
    {
      mystuff.gpu_type = GPU_GCN;
    }
I want to make it so that the GPU names are in an array of strings, so anyone who wants to make changes only has to add a string to an array instead of having to modify the conditionals. It won't make a big difference to developers, but I think it's good programming practice.

Quote:
This works fine for me using gcc 8.3.1
Code:
#include <iostream>

int main(int argc, char* argv[])
{
    const char* str_arr[] = { "blah", "blah blah", "a b c d e" };
    for (const char* s : str_arr)
    {
        std::cout << s << std::endl;
    }

    return 0;
}
Unfortunately, this doesn't work for me. I'm getting the following error:

Code:
cannot build range expression with array function
      parameter 'device_class' since parameter with array type 'char *[]' is
      treated as pointer type 'char **'
This is my code for reference:

Code:
const char *TYPE_GCN[] = {
  "Capeverde",
  "Pitcairn",
  "Bonaire",
  "Oland",
  "Sun",
  "Mars",
  "Venus",
  "Saturn",
  "Neptune",
  "Curacao",
  "Tonga",
  "Hainan",
  "Kalindi"
};

[...]

/* check if device name contains a string in the array */
int name_contains(char *device_name, char *device_class[]) {
  for (const char *device : device_class) {
    if (strstr(device_name, device)) {
      return 1;
    }
  }
  return 0;
}

Last fiddled with by ixfd64 on 2019-06-27 at 23:40
ixfd64 is online now   Reply With Quote
Old 2019-06-27, 23:58   #6
ewmayer
2ω=0
 
ewmayer's Avatar
 
Sep 2002
Rep├║blica de California

2×5,647 Posts
Default

As others have noted sizeof() is useless for getting number of array elements. In that sense, a C++ vector<string> is preferable. Strictly in C, you need some kind of end-of-array sentinel. Here an example using an empty string (which will still occupy storage via the resulting string-terminator char), with 2 ways to iterate over the string array:
Code:
#include <stdio.h>
#include <string.h>
#define	STRNEQ(s1,s2)	( strcmp(s1,s2))
int main()
{
	char *str_arr[] = {"foo","bar",""};
	char **curr_str;
	for(curr_str = str_arr; STRNEQ(*curr_str,""); curr_str++)
		printf("curr_strA = %s\n",*curr_str);
	int i;
	for(i = 0; STRNEQ(str_arr[i],""); i++)
		printf("curr_strB = %s\n",str_arr[i]);
	return 0;
}
ewmayer is online now   Reply With Quote
Old 2019-06-28, 00:42   #7
rogue
 
rogue's Avatar
 
"Mark"
Apr 2003
Between here and the

580010 Posts
Default

Making a check for specific GPU names is not future-proof.

For OpenCL you can use clGetDeviceInfo() to determine the features available to the GPU. You can then use those features to determine which kernel you want to execute.

My knowledge of OpenCL is only strong enough for me to use it with some of the programs using the mtsieve framework. I wouldn't be surprised if your OpenCL skills were much better.
rogue is offline   Reply With Quote
Old 2019-06-28, 01:21   #8
ixfd64
Bemusing Prompter
 
ixfd64's Avatar
 
"Danny"
Dec 2002
California

8E616 Posts
Default

Quote:
Originally Posted by rogue View Post
Making a check for specific GPU names is not future-proof.

For OpenCL you can use clGetDeviceInfo() to determine the features available to the GPU. You can then use those features to determine which kernel you want to execute.
Thanks for the information. That looks like an even better way to handle kernel features.

Quote:
My knowledge of OpenCL is only strong enough for me to use it with some of the programs using the mtsieve framework. I wouldn't be surprised if your OpenCL skills were much better.
Unfortunately, I actually don't have any OpenCL experience at all. :\

Last fiddled with by ixfd64 on 2019-06-28 at 01:29
ixfd64 is online now   Reply With Quote
Old 2019-06-28, 08:01   #9
ldesnogu
 
ldesnogu's Avatar
 
Jan 2008
France

17·31 Posts
Default

Quote:
Originally Posted by ewmayer View Post
As others have noted sizeof() is useless for getting number of array elements. In that sense, a C++ vector<string> is preferable. Strictly in C, you need some kind of end-of-array sentinel. Here an example using an empty string (which will still occupy storage via the resulting string-terminator char), with 2 ways to iterate over the string array:
Code:
#include <stdio.h>
#include <string.h>
#define    STRNEQ(s1,s2)    ( strcmp(s1,s2))
int main()
{
    char *str_arr[] = {"foo","bar",""};
    char **curr_str;
    for(curr_str = str_arr; STRNEQ(*curr_str,""); curr_str++)
        printf("curr_strA = %s\n",*curr_str);
    int i;
    for(i = 0; STRNEQ(str_arr[i],""); i++)
        printf("curr_strB = %s\n",str_arr[i]);
    return 0;
}
You don't really need a sentinel for an array declared at compile time. You can get the numbers of elements with something like sizeof(array)/sizeof(array[0]):
Code:
#include <stdio.h>

int main()
{
    char *str_arr[] = {"foo","bar"};
    for (int i = 0; i < sizeof(str_arr) / sizeof(str_arr[0]); i++)
       printf("curr_strA = %s\n", str_arr[i]);
    return 0;
}

Last fiddled with by ldesnogu on 2019-06-28 at 08:04
ldesnogu is offline   Reply With Quote
Old 2019-06-28, 13:34   #10
rogue
 
rogue's Avatar
 
"Mark"
Apr 2003
Between here and the

23×52×29 Posts
Default

Quote:
Originally Posted by ixfd64 View Post
Thanks for the information. That looks like an even better way to handle kernel features.

Unfortunately, I actually don't have any OpenCL experience at all. :\
In that case I might be able to help you. Feel free to reach out to me via PM.
rogue is offline   Reply With Quote
Old 2019-06-28, 23:43   #11
ixfd64
Bemusing Prompter
 
ixfd64's Avatar
 
"Danny"
Dec 2002
California

2×17×67 Posts
Default

Quote:
Originally Posted by ldesnogu View Post
You can get the numbers of elements with something like sizeof(array)/sizeof(array[0]):
Code:
#include <stdio.h>

int main()
{
    char *str_arr[] = {"foo","bar"};
    for (int i = 0; i < sizeof(str_arr) / sizeof(str_arr[0]); i++)
       printf("curr_strA = %s\n", str_arr[i]);
    return 0;
}
I tried that too, but it always returns 1.
ixfd64 is online now   Reply With Quote
Reply

Thread Tools


Similar Threads
Thread Thread Starter Forum Replies Last Post
Simple factoring challenge + questions siegert81 Factoring 12 2016-05-28 18:36
Programming questions Xyzzy Programming 76 2015-01-24 04:35
Need some help on php programming pinhodecarlos Programming 2 2012-07-23 18:17
New to programming. What to do? lorgix Miscellaneous Math 9 2010-12-08 22:22
plz, help me in c programming alaa Homework Help 12 2007-06-12 22:17

All times are UTC. The time now is 05:47.

Fri Jul 10 05:47:19 UTC 2020 up 107 days, 3:20, 0 users, load averages: 1.30, 1.34, 1.29

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.

This forum has received and complied with 0 (zero) government requests for information.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation.
A copy of the license is included in the FAQ.